# CTFZone 2018 -- Buggy PWN> **Category**: PWN > **Description**:> A disgruntled employee has recently left our team. Unfortunately, he took a> flag with him. We've discovered that there is strange buggy service currently> in development on his server. Maybe you can get the flag from there.> nc pwn-02.v7frkwrfyhsjtbpfcppnu.ctfz.one 1337 > **Attachment**: buggy\_pwn.py
# WriteupWe are given the address to connect and the source code of the applicationrunning on the server, so you can test all your exploits and scripts on yourmachine, which you are going to do.
When you connect to the server, you are asked to enter N lines. If you try todo this, you will most certainly get an exception. So there is no use talkingto the server without exploring its source code. Upon opening it you see thatit's a virtual machine with a made-up architecutre. If you were me you wouldprobably go right to its opcode handling and commands which start at line 345.It's a good idea to walk through all commands and put some debug informationinto them like this:```def __command_xor(self,amplifier):    inreg=amplifier&0xf    outreg=amplifier>>4    stderr.print("xor %s %s\n" % (self.reg_names[inreg], self,reg_names[outreg]))    #first define reg_names similarly to dataregs```You can then enhance this debug information with values of registers andconstants etc.
You will then connect to your server with those prints everywhere andunderstand that it expects a you to send a line of length 16 exactly. You willtry to send a line and will encounter the same exception. Now it's time to diveinto operations of the memory of the machine
## MemoryThe comment at the beginning gives you a clue that it's a 2d memory plane,where taking a value requires not one address, but two coordinates, which is areally cool idea. Reading and writing in memory take two (4) arguments: 2dcoordinates of start and direction in form of vector that is added tocoordinates on each next cell read. Also each cell is a pair of two C bytes,and numbers are C dwords with the same way of marking the sign on number. Sowhen the program invited you to write 16 cells, you were supposed to send 32bytes of text. Also as you saw when you explored command operations, the stringyou send must consist of **only** printable ascii characters.
## Program logicAll this knowledge is enough to understand that the program is the following:invite you to write an arbitrary amount of 32 byte strings to memory, eachgoing below the previous, then it will invite you to write a string of suppliedlength to stack, which is an obvious set-up to exploit the following retcommand. Using this you can overwrite the return address on stack and jumpright into the memory you just filled up with strings of length 16. You thenturn your attention to the 0x40 syscall which will print you the flag when someconditions are met: `eax = ('f'.ord, 'l'.ord), ebx = ('a'.ord, 'g'.ord)`.
Let's reiterate some constraints: you can only send printable strings, so theshellcode must be printable. The strings must be of length 32 bytes. Even more,when eip goes beyond one string, the machine halts, so you need to find a wayto redirect execution to another string or in another direction. Oh, and youare limited vertically by 59 strings, but that won't be a problem.
## ExploitFirst let's form a payload to jump to controlled memory. After carefully calculating bytes you arrive at something like this:```payload = "a"*32 + "\x40" + chr(0x45)sock.send(payload + "\n")print sock.recv(100500)```Notice that we only overwrite the least significant bytes of return address, asthe other bytes are already there and are not printable.
The shellcode will be something like this: we load the required values into eaxand ebx xorred with some printable string so that we get another printablestring. We then load the xor-string into ecx, xor ecx with eax and ebx, andcall the flagcall. The values we take are, for example, the following:```xorchar = chr(0b1000000)xorord = ord(xorchar)eax_val = chr(ord("f")^xorord) + chr(ord("l")^xorord) + xorchar*6ebx_val = chr(ord("a")^xorord) + chr(ord("g")^xorord) + xorchar*6ecx_val = xorchar * 8```Sounds nice. After calculating bytes, though, you understand that thisshellcode is exactly 36 bytes, which is 4 above the limit, so we need to find away to redirect the execution after all. We will achieve this with rotip command, which we can use to redirect execution to read cells not left to right, but top to bottom.
Notice, however, that the pwn is buggy: after using rotip in this way, it willstill read the next command to the right, and only after that it will go in thedesired direction, so be careful with positioning your shellcode in memory. Youcan find my example script [here](./send.py). You can also send all strings by hand, as they are not many. Congratulations, you got the flag!