An introduction to PEDA and Pwntools

BadB

Professional
Messages
1,883
Reaction score
1,924
Points
113
In this article we will talk about PEDA. No, not about those “pedas”, no, be alarmed, but about Python Exploit Development Assistance, a very handy kit for creating exploits and the basics of working with it.

I bring to your attention a free translation of a series of articles: https://github.com/nnamon/linux-exploitation-course

Preliminary preparation:
  1. Understanding the architecture and language of the intel x86-64 assembly language
  2. Knowledge of the GDB debugger
  3. Knowledge of C and Python
  4. Understanding the Jump Mechanism in Shellcode
  5. Ability to work with virtual machines and virtual environment

Course plan:
  1. Introduction to PEDA and Pwntools
  2. An Introduction to Return-Oriented Programming
  3. Classic vulnerability exploitation techniques
  4. Linux binary file security mechanisms
  5. Bypassing NX Using the Return Oriented Programming Technique
  6. Bypassing NX using Ret2Libc
  7. ASLR from the inside
  8. Bypass ASLR / NX using Ret2PLT
  9. Bypass ASLR / NX using GOT rewrite
  10. Complex (multi-stage) exploits
  11. String formatting vulnerabilities
  12. Additional exercises
To work, you need a VMWare virtual machine (https://www.vmware.com/products/workstation-pro/workstation-pro-evaluation.html) or VirtualBox (https://www.virtualbox.org/wiki/Downloads) and your favorite Linux distribution like Kali ( https://www.kali.org/downloads/)

Configure convenient access to the virtual machine console via SSH or Telnet, since the main magic will be done using the command line.

We will also need additional files for the exercises. Download them to any convenient folder:
Code:
root@kali:~# git clone https://github.com/nnamon/linux-exploitation-course

And so, they drove ...

Introduction to PEDA and Pwntools

GDB with the PEDA plugin and Pwntools are two utilities that will be very heavily used throughout the course. Now let's figure out what's what and see how they work.

Our test subjects will be the already assembled binary files that we have successfully downloaded at the preparation stage. Let's move to the desired directory:
Code:
root@kali:~# cd linux-exploitation-course/lessons/3_intro_to_tools/build

Well, let's run the experimental sample:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/build# ./1_sample
Hello, I am a sample program.

PEDA

PEDA (Python Exploit Development Assistance) is an extension for GDB debugger that adds a bunch of splash of additional functions, increasing the efficiency and usability of the debugger.

To install PEDA, just run a couple of commands:
Code:
root@kali:~# git clone https://github.com/longld/peda.git ~/peda
root@kali:~# echo "source ~/peda/peda.py" >> ~/.gdbinit

Well, now you can test it with an example. Let's start GDB to debug our binary:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/build# gdb ./1_sample
GNU gdb (Debian 8.2.1-2) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./1_sample...(no debugging symbols found)...done.
Code:
gdb-peda$ r
Starting program: /root/linux-exploitation-course/lessons/3_intro_to_tools/build/1_sample
Hello, I am a sample program.
[Inferior 1 (process 3297) exited normally]
Warning: not running
Code:
gdb-peda$

The command line should show gdb-peda $, if it doesn't, then something went wrong during the plugin installation stage. Let's put a breakpoint at the very beginning on the main function and run it for execution:
Code:
gdb-peda$ br main
Breakpoint 1 at 0x40052a
gdb-peda$ r
Starting program: /root/linux-exploitation-course/lessons/3_intro_to_tools/build/1_sample
[----------------------------------registers-----------------------------------]
RAX: 0x400526 (<main>: push rbp)
RBX: 0x0
RCX: 0x7ffff7fab718 --> 0x7ffff7facd80 --> 0x0
RDX: 0x7fffffffe518 --> 0x7fffffffe791 ("SHELL=/bin/bash")
RSI: 0x7fffffffe508 --> 0x7fffffffe749 ("/root/linux-exploitation-course/lessons/3_intro_to_tools/build/1_sample")
RDI: 0x1
RBP: 0x7fffffffe420 --> 0x400540 (<__libc_csu_init>: push r15)
RSP: 0x7fffffffe420 --> 0x400540 (<__libc_csu_init>: push r15)
RIP: 0x40052a (<main+4>: mov edi,0x4005c4)
R8 : 0x7ffff7facd80 --> 0x0
R9 : 0x7ffff7facd80 --> 0x0
R10: 0xfffffffffffff35c
R11: 0x7ffff7e13fb0 (<__libc_start_main>: push r14)
R12: 0x400430 (<_start>: xor ebp,ebp)
R13: 0x7fffffffe500 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x400521 <frame_dummy+33>: jmp 0x4004a0 <register_tm_clones>
0x400526 <main>: push rbp
0x400527 <main+1>: mov rbp,rsp
=> 0x40052a <main+4>: mov edi,0x4005c4
0x40052f <main+9>: call 0x400400 <puts@plt>
0x400534 <main+14>: mov eax,0x0
0x400539 <main+19>: pop rbp
0x40053a <main+20>: ret
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe420 --> 0x400540 (<__libc_csu_init>: push r15)
0008| 0x7fffffffe428 --> 0x7ffff7e1409b (<__libc_start_main+235>: mov edi,eax)
0016| 0x7fffffffe430 --> 0x0
0024| 0x7fffffffe438 --> 0x7fffffffe508 --> 0x7fffffffe749 ("/root/linux-exploitation-course/lessons/3_intro_to_tools/build/1_sample")
0032| 0x7fffffffe440 --> 0x100100000
0040| 0x7fffffffe448 --> 0x400526 (<main>: push rbp)
0048| 0x7fffffffe450 --> 0x0
0056| 0x7fffffffe458 --> 0xa3601b7a6a4817f7
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Breakpoint 1, 0x000000000040052a in main ()
gdb-peda$

It should be cool, you can see the stack, code, registers. Note that when you step through the code, the picture will be updated and the dynamics of execution will be visible, which is very convenient. PEDA has a bunch of interesting things in stock, the full list can be viewed by running the peda command:
Code:
gdb-peda$ peda
PEDA - Python Exploit Development Assistance for GDB
For latest update, check peda project page: https://github.com/longld/peda/

List of "peda" subcommands, type the subcommand to invoke it:
aslr -- Show/set ASLR setting of GDB
asmsearch -- Search for ASM instructions in memory
assemble -- On the fly assemble and execute instructions using NASM
breakrva -- Set breakpoint by Relative Virtual Address (RVA)
checksec -- Check for various security options of binary
cmpmem -- Compare content of a memory region with a file
context -- Display various information of current execution context
context_code -- Display nearby disassembly at $PC of current execution context
context_register -- Display register information of current execution context
context_stack -- Display stack of current execution context
crashdump -- Display crashdump info and save to file
deactive -- Bypass a function by ignoring its execution (eg sleep/alarm)
distance -- Calculate distance between two addresses
dumpargs -- Display arguments passed to a function when stopped at a call instruction
dumpmem -- Dump content of a memory region to raw binary file
dumprop -- Dump all ROP gadgets in specific memory range
eflags -- Display/set/clear/toggle value of eflags register
elfheader -- Get headers information from debugged ELF file
elfsymbol -- Get non-debugging symbol information from an ELF file
gennop -- Generate abitrary length NOP sled using given characters
getfile -- Get exec filename of current debugged process
getpid -- Get PID of current debugged process
goto -- Continue execution at an address
help -- Print the usage manual for PEDA commands
hexdump -- Display hex/ascii dump of data in memory
hexprint -- Display hexified of data in memory
jmpcall -- Search for JMP/CALL instructions in memory
loadmem -- Load contents of a raw binary file to memory
lookup -- Search for all addresses/references to addresses which belong to a memory range
nearpc -- Disassemble instructions nearby current PC or given address
nextcall -- Step until next 'call' instruction in specific memory range
nextjmp -- Step until next 'j*' instruction in specific memory range
nxtest -- Perform real NX test to see if it is enabled/supported by OS
patch -- Patch memory start at an address with string/hexstring/int
pattern -- Generate, search, or write a cyclic pattern to memory
pattern_arg -- Set argument list with cyclic pattern
pattern_create -- Generate a cyclic pattern
pattern_env -- Set environment variable with a cyclic pattern
pattern_offset -- Search for offset of a value in cyclic pattern
pattern_patch -- Write a cyclic pattern to memory
pattern_search -- Search a cyclic pattern in registers and memory
payload -- Generate various type of ROP payload using ret2plt
pdisass -- Format output of gdb disassemble command with colors
pltbreak -- Set breakpoint at PLT functions match name regex
procinfo -- Display various info from /proc/pid/
profile -- Simple profiling to count executed instructions in the program
pyhelp -- Wrapper for python built-in help
readelf -- Get headers information from an ELF file
refsearch -- Search for all references to a value in memory ranges
reload -- Reload PEDA sources, keep current options untouch
ropgadget -- Get common ROP gadgets of binary or library
ropsearch -- Search for ROP gadgets in memory
searchmem -- Search for a pattern in memory; support regex search
session -- Save/restore a working gdb session to file as a script
set -- Set various PEDA options and other settings
sgrep -- Search for full strings contain the given pattern
shellcode -- Generate or download common shellcodes.
show -- Show various PEDA options and other settings
skeleton -- Generate python exploit code template
skipi -- Skip execution of next count instructions
snapshot -- Save/restore process's snapshot to/from file
start -- Start debugged program and stop at most convenient entry
stepuntil -- Step until a desired instruction in specific memory range
strings -- Display printable strings in memory
substr -- Search for substrings of a given string/number in memory
telescope -- Display memory content at an address with smart dereferences
tracecall -- Trace function calls made by the program
traceinst -- Trace specific instructions executed by the program
unptrace -- Disable anti-ptrace detection
utils -- Miscelaneous utilities from utils module
vmmap -- Get virtual mapping address ranges of section(s) in debugged process
waitfor -- Try to attach to new forked process; mimic "attach -waitfor"
xinfo -- Display detail information of address/registers
xormem -- XOR a memory region with a key
xprint -- Extra support to GDB's print command
xrefs -- Search for all call/data access references to a function/variable
xuntil -- Continue execution until an address or function
Type "help" followed by subcommand for full documentation.

Let's take a look at some particularly interesting commands.

checksec

This command lists the security mechanisms that are enabled and used for a binary file. Very handy when developing your exploit:
Code:
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial

distance

Often during the development of your shellcode, you need to calculate the distance in bytes (distance) between addresses, this command is used to quickly find the distance:
Code:
gdb-peda$ distance 0x7fffffffe4f0 0x7fffffffe528
From 0x7fffffffe4f0 to 0x7fffffffe528: 56 bytes, 14 dwords
gdb-peda$

elfsymbol

In the event that you need to find the address of a specific debug symbol, you can use this command:
Code:
gdb-peda$ elfsymbol
Found 2 symbols
puts@plt = 0x400400
__libc_start_main@plt = 0x400410
gdb-peda$

pattern

The pattern generator is one of the coolest frequently used functions. This command generates a de Bruijn sequence of the desired length. A de Bruijn sequence is a sequence that has unique subsequences of length n at any of its points (or something like that).

In our case, we will be interested in unique sequences of length 4, since the registers are 32-bit (4 bytes). It is especially effective in finding offsets at which data is written to registers.

Let's create a pattern of size 64:
Code:
gdb-peda$ pattern create 64
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAH'
gdb-peda$

Imagine that we caused a buffer overflow and determined that the progress bar crashed at 0x48414132 ('2AAH' in ASCII). We can determine the exact offset of our data in order to place the address to redirect the flow of execution.

Code:
gdb-peda$ pattern offset 0x48414132
1212236082 found at offset: 60
gdb-peda$ pattern offset 2AAH
2AAH found at offset: 60
gdb-peda$

procinfo

This command prints information from the / proc / pid / x directory directly to the console:
Code:
gdb-peda$ procinfo
exe = /vagrant/lessons/3_intro_to_tools/build/1_sample
fd[0] -> /dev/pts/0
fd[1] -> /dev/pts/0
fd[2] -> /dev/pts/0
pid = 11038
ppid = 11028
uid = [1000, 1000, 1000, 1000]
gid = [1000, 1000, 1000, 1000]

Convenient to see which descriptors are open

vmmap

This command displays the memory mapping of the process:
Code:
gdb-peda$ vmmap
Start End Perm Name
0x00400000 0x00401000 r-xp /vagrant/lessons/3_intro_to_tools/build/1_sample
0x00600000 0x00601000 r--p /vagrant/lessons/3_intro_to_tools/build/1_sample
0x00601000 0x00602000 rw-p /vagrant/lessons/3_intro_to_tools/build/1_sample
0x00007ffff7a0e000 0x00007ffff7bcd000 r-xp /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7bcd000 0x00007ffff7dcd000 ---p /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7dcd000 0x00007ffff7dd1000 r--p /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7dd1000 0x00007ffff7dd3000 rw-p /lib/x86_64-linux-gnu/libc-2.23.so
0x00007ffff7dd3000 0x00007ffff7dd7000 rw-p mapped
0x00007ffff7dd7000 0x00007ffff7dfd000 r-xp /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7fec000 0x00007ffff7fef000 rw-p mapped
0x00007ffff7ff6000 0x00007ffff7ff8000 rw-p mapped
0x00007ffff7ff8000 0x00007ffff7ffa000 r--p [vvar]
0x00007ffff7ffa000 0x00007ffff7ffc000 r-xp [vdso]
0x00007ffff7ffc000 0x00007ffff7ffd000 r--p /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7ffd000 0x00007ffff7ffe000 rw-p /lib/x86_64-linux-gnu/ld-2.23.so
0x00007ffff7ffe000 0x00007ffff7fff000 rw-p mapped
0x00007ffffffde000 0x00007ffffffff000 rw-p [stack]
0xffffffffff600000 0xffffffffff601000 r-xp [vsyscall]
gdb-peda$

Of the important, it is worth paying attention to the access flag for memory segments. Very often, when developing an exploit, you need to place all sorts of different data: shellcode, pointers, and so on. In this case, you need to make sure that the memory area is available for writing.

find aka searchmem

The find command is used to find the desired pattern in memory.

For example, the line “/ bin / sh” is often encountered. Let's try to find it using the find command:
Code:
gdb-peda$ find /bin/sh
Searching for '/bin/sh' in: None ranges
Found 1 results, display max 1 items:
libc : 0x7ffff7b9a177 --> 0x68732f6e69622f ('/bin/sh')
gdb-peda$

Let's continue our acquaintance with the necessary tools.

Pwntools

Pwntools is a python library that allows you to write exploits efficiently and quickly. It is used very often in CTF. Now we will figure out how to work with it.

First of all, you need to put it. Although the developers write that it is better to use python3, the library did not take off on my 3rd python.

It turned out to be put like this:
Code:
root@kali:~# apt-get update
root@kali:~# apt-get install python2.7 python-pip python-dev git libssl-dev libffi-dev build-essential ipython
root@kali:~# pip2 install --upgrade pip
root@kali:~# pip2 install pwntools

How to use Pwntools

There are three ways to use it:
  1. Interactively via python / iPython console
  2. Directly in a python script
  3. Pwntools command line utility
Method 1. Interactive through the console

Often, when writing an exploit, there is a need to quickly check something without creating a full-fledged script. The iPython Console is a great way to learn the Pwntools API:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/build# ipython
Python 2.7.17 (default, Oct 19 2019, 23:36:22)
Type "copyright", "credits" or "license" for more information.
IPython 5.8.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: from pwn import *
In [2]:

IPython has auto-completion and a built-in system for finding keywords in the documentation. For example, if we want to see what the p32 function does, we just use the symbol?:
Code:
In [4]: p32?
Signature: p32(*a, **kw)
Docstring:
p32(number, sign, endian, ...) -> str
Packs an 32-bit integer
Arguments:
number (int): Number to convert
endianness (str): Endianness of the converted integer ("little"/"big")
sign (str): Signedness of the converted integer ("unsigned"/"signed")
kwargs (dict): Arguments passed to context.local(), such as
``endian`` or ``signed``.
Returns:
The packed number as a string
File: /usr/local/lib/python2.7/dist-packages/pwnlib/context/__init__.py
Type: function
In [5]: p32(0x41424344)
Out[5]: 'DCBA'
In [6]:

Method 2. In a python script

First, let's use this template:
Code:
#!/usr/bin/python
from pwn import *
def main():
pass
if __name__ == '__main__':
main()

Let's try to call the Pwntools API from the script:
Code:
#!/usr/bin/python
from pwn import *
def main():
p = process("/bin/sh")
p.interactive()
if __name__ == '__main__':
main()

Let's run the script:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/scripts# python 2_shellsample.py
[+] Starting local process '/bin/sh': pid 39116
[*] Switching to interactive mode
$ id
uid=0(root) gid=0(root) groups=0(root)
$

Method 3. Pwntools command line tools

Pwntools installs the pwn script in the / usr / local / bin directory. For a list of commands, just run pwn -h:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/scripts# pwn -h
usage: pwn [-h]
{asm,checksec,constgrep,cyclic,debug,disasm,disablenx,elfdiff,elfpatch,errno,hex,phd,pwnstrip,scramble,shellcraft,template,unhex,update}
...
Pwntools Command-line Interface
positional arguments:
{asm,checksec,constgrep,cyclic,debug,disasm,disablenx,elfdiff,elfpatch,errno,hex,phd,pwnstrip,scramble,shellcraft,template,unhex,update}
asm Assemble shellcode into bytes
checksec Check binary security settings
constgrep Looking up constants from header files. Example:
constgrep -c freebsd -m ^PROT_ '3 + 4'
cyclic Cyclic pattern creator/finder
debug Debug a binary in GDB
disasm Disassemble bytes into text format
disablenx Disable NX for an ELF binary
elfdiff Compare two ELF files
elfpatch Patch an ELF file
errno Prints out error messages
hex Hex-encodes data provided on the command line or stdin
phd Pwnlib HexDump
pwnstrip Strip binaries for CTF usage
scramble Shellcode encoder
shellcraft Microwave shellcode -- Easy, fast and delicious
template Generate an exploit template
unhex Decodes hex-encoded data provided on the command line
or via stdin.
update Check for pwntools updates
optional arguments:
-h, --help show this help message and exit

The full documentation is available here: https://docs.pwntools.com/en/stable/commandline.html

Interacting with executable files

There are many attack vectors, let's focus on remotely running executables that we have access to over the network.

First, let's see how we can interact with a local copy of a file that takes a string from stdin as input and returns the result to stdout.

Local copy of the executable file

Let's try to run the following file:

Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/build# ./2_interactive
Welcome to the Super Secure Shell
Password: HelloWorld?
Incorrect password!

Here is the source code of the executable file:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void give_shell() {
system("/bin/sh");
}
int main() {
// Disable buffering on stdin and stdout to make network connections better.
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
char * password = "TheRealPassword";
char user_password[200];
puts("Welcome to the Super Secure Shell");
printf("Password: ");
scanf("%199s", user_password);
if (strcmp(password, user_password) == 0) {
puts("Correct password!");
give_shell();
}
else {
puts("Incorrect password!");
}
}

The main task of the program is to compare the entered data and the password string. If they match, then the shell is launched:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/build# ./2_interactive
Welcome to the Super Secure Shell
Password: TheRealPassword
Correct password!
# id
uid=0(root) gid=0(root) groups=0(root)
#

Now we have realized what needs to be sent as input. Let's write a simple exploit using Pwntools:
Code:
#!/usr/bin/python
from pwn import *
def main():
# Start a local process
p = process("../build/2_interactive")
# Get rid of the prompt
data1 = p.recvrepeat(0.2)
log.info("Got data: %s" % data1)
# Send the password
p.sendline("TheRealPassword")
# Check for success or failure
data2 = p.recvline()
log.info("Got data: %s" % data2)
if "Correct" in data2:
# Hand interaction over to the user if successful
log.success("Success! Enjoy your shell!")
p.interactive()
else:
log.failure("Password was incorrect.")
if __name__ == "__main__":
main()

Take some time to understand how the script works. Notice the line process (“../ build / 2_interactive”). It starts a new process and allows you to interact with the process like a socket. Let's run the script to make sure everything works:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/scripts# python 3_interactive.py
[+] Starting local process '../build/2_interactive': pid 39170
[*] Got data: Welcome to the Super Secure Shell
Password:
[*] Got data: Correct password!
[+] Success! Enjoy your shell!
[*] Switching to interactive mode
$ id
uid=0(root) gid=0(root) groups=0(root)
$ ls -al
total 36
drwxr-xr-x 2 root root 4096 Jan 5 17:12 .
drwxr-xr-x 6 root root 4096 Jan 5 17:12 ..
-rw-r--r-- 1 root root 98 Jan 5 17:12 1_template.py
-rw-r--r-- 1 root root 136 Jan 5 17:12 2_shellsample.py
-rw-r--r-- 1 root root 628 Jan 5 17:12 3_interactive.py
-rw-r--r-- 1 root root 663 Jan 5 17:12 4_networked.py
-rw-r--r-- 1 root root 412 Jan 5 17:12 5_gdb.py
-rw-r--r-- 1 root root 369 Jan 5 17:12 6_gdbsol.py
-rw-r--r-- 1 root root 363 Jan 5 17:12 7_gdbremote.py
$
[*] Interrupted
[*] Stopped process '../build/2_interactive' (pid 39170)

Modeling a network application

First, we will create a new screen session to start our server using the socat utility:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/scripts# screen bash
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/scripts#

Now let's start the server itself, port 1330:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/scripts# socat TCP4-listen:1330,reuseaddr,fork EXEC:./2_interactive

That's all for now. Let's go back to our first bash session with the keyboard shortcut: CTRL-AD.

In order to check that the server is running on port 1330, we can run netcat:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/scripts# nc localhost 1330
Welcome to the Super Secure Shell
Password: Hello
Incorrect password!

Now let's modify the first script that worked with binaries. Just comment out the line for starting the process (), and add remote (“localhost”, 1330):
Code:
#!/usr/bin/python
from pwn import *
def main():
# Start a local process
#p = process("../build/2_interactive")
p = remote("localhost", 1330)
# Get rid of the prompt
data1 = p.recvrepeat(0.2)
log.info("Got data: %s" % data1)
# Send the password
p.sendline("TheRealPassword")
# Check for success or failure
data2 = p.recvline()
log.info("Got data: %s" % data2)
if "Correct" in data2:
# Hand interaction over to the user if successful
log.success("Success! Enjoy your shell!")
p.interactive()
else:
log.failure("Password was incorrect.")
if __name__ == "__main__":
main()

We check:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/scripts# python 4_networked.py
[+] Opening connection to localhost on port 1330: Done
[*] Got data: Welcome to the Super Secure Shell
Password:
[*] Got data: Correct password!
[+] Success! Enjoy your shell!
[*] Switching to interactive mode
$ id
uid=0(root) gid=0(root) groups=0(root)
$ ls -al
total 36
drwxr-xr-x 2 root root 4096 Jan 5 17:12 .
drwxr-xr-x 6 root root 4096 Jan 5 17:12 ..
-rw-r--r-- 1 root root 98 Jan 5 17:12 1_template.py
-rw-r--r-- 1 root root 136 Jan 5 17:12 2_shellsample.py
-rw-r--r-- 1 root root 628 Jan 5 17:12 3_interactive.py
-rw-r--r-- 1 root root 663 Jan 5 17:12 4_networked.py
-rw-r--r-- 1 root root 412 Jan 5 17:12 5_gdb.py
-rw-r--r-- 1 root root 369 Jan 5 17:12 6_gdbsol.py
-rw-r--r-- 1 root root 363 Jan 5 17:12 7_gdbremote.py
$
[*] Closed connection to localhost port 1330

Debugging with GDB

Pwntools includes GDB functionality, for its study it is better to go through the off documentation: http://docs.pwntools.com/en/stable/gdb.html

Let's try:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/build# ./3_reversing
Name: This is a Name
Token: AAAA
Submitted Name: This is a Name
Submitted Token: 0x41414141
Incorrect credentials.

To better understand what's going on, you can use the ltrace utility:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/build# apt install ltrace
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/build# ltrace ./3_reversing
__libc_start_main(0x4007b1, 1, 0x7ffcb8734588, 0x4008f0 <unfinished ...>
setvbuf(0x7f38691b7a00, 0, 2, 0) = 0
setvbuf(0x7f38691b8760, 0, 2, 0) = 0
printf("Name: "Name: ) = 6
read(0This is a Name
, "This is a Name\n", 63) = 15
printf("Token: "Token: ) = 7
read(0AAAA
, "AAAA", 4) = 4
printf("Submitted Name: %s\n", "This is a Name\n"Submitted Name: This is a Name
) = 32
printf("Submitted Token: 0x%x\n", 0x41414141Submitted Token: 0x41414141
) = 28
strcmp("Santo & Johnny", "This is a Name\n") = -1
puts("Incorrect credentials."Incorrect credentials.
) = 23
+++ exited (status 0) +++

Using the following script, we can display the process id before interacting with it:
Code:
#!/usr/bin/python
from pwn import *
def main():
# Start a new process
p = process("../build/3_reversing")
# Name and Token
name = "Test Name".ljust(63, "\x00")
token = 0x41414141
# Print pid
raw_input(str(p.proc.pid))
# Send name and token
p.send(name)
p.send(p32(token))
# Start an interactive session
p.interactive()
if __name__ == "__main__":
main()

Now let's start another SSH session and run our script:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/scripts# python 5_gdb.py
[+] Starting local process '../build/3_reversing': Done
5652

Let's go back to the previous bash session and start GDB. Now we can connect directly to the process:
Code:
root@kali:~/linux-exploitation-course/lessons/3_intro_to_tools/scripts# gdb
GNU gdb (Debian 8.2.1-2) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word".
gdb-peda$ attach 5652
Attaching to process 5652
Reading symbols from /vagrant/lessons/3_intro_to_tools/build/3_reversing...(no debugging symbols found)...done.
Reading symbols from /lib/x86_64-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/libc-2.23.so...done.
done.
Reading symbols from /lib64/ld-linux-x86-64.so.2...Reading symbols from /usr/lib/debug//lib/x86_64-linux-gnu/ld-2.23.so...done.
done.
[----------------------------------registers-----------------------------------]
RAX: 0xfffffffffffffe00
RBX: 0x0
RCX: 0x7f2156e17680 (<__read_nocancel+7>: cmp rax,0xfffffffffffff001)
RDX: 0x3f ('?')
RSI: 0x7ffc16545500 --> 0x0
RDI: 0x0
RBP: 0x7ffc16545550 --> 0x4008f0 (<__libc_csu_init>: push r15)
RSP: 0x7ffc165454e8 --> 0x400844 (<main+147>: mov edi,0x40098a)
RIP: 0x7f2156e17680 (<__read_nocancel+7>: cmp rax,0xfffffffffffff001)
R8 : 0x7f2157304700 (0x00007f2157304700)
R9 : 0x6
R10: 0x37b
R11: 0x246
R12: 0x400680 (<_start>: xor ebp,ebp)
R13: 0x7ffc16545630 --> 0x1
R14: 0x0
R15: 0x0
EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x7f2156e17677 <read+7>: jne 0x7f2156e17689 <read+25>
0x7f2156e17679 <__read_nocancel>: mov eax,0x0
0x7f2156e1767e <__read_nocancel+5>: syscall
=> 0x7f2156e17680 <__read_nocancel+7>: cmp rax,0xfffffffffffff001
0x7f2156e17686 <__read_nocancel+13>: jae 0x7f2156e176b9 <read+73>
0x7f2156e17688 <__read_nocancel+15>: ret
0x7f2156e17689 <read+25>: sub rsp,0x8
0x7f2156e1768d <read+29>: call 0x7f2156e354e0 <__libc_enable_asynccancel>
[------------------------------------stack-------------------------------------]
0000| 0x7ffc165454e8 --> 0x400844 (<main+147>: mov edi,0x40098a)
0008| 0x7ffc165454f0 --> 0x0
0016| 0x7ffc165454f8 --> 0x4141414100000000 ('')
0024| 0x7ffc16545500 --> 0x0
0032| 0x7ffc16545508 --> 0x0
0040| 0x7ffc16545510 --> 0x0
0048| 0x7ffc16545518 --> 0x0
0056| 0x7ffc16545520 --> 0x0
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x00007f2156e17680 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84
84 ../sysdeps/unix/syscall-template.S: No such file or directory.
gdb-peda$

The program stopped somewhere in the libc library. We can set our breakpoints. Let's assume that we have already determined where the input data is passed to the check_creds () function using the reverse method:
Code:
gdb-peda$ disas check_creds
Dump of assembler code for function check_creds:
0x0000000000400776 <+0>: push rbp
0x0000000000400777 <+1>: mov rbp,rsp
0x000000000040077a <+4>: sub rsp,0x10
0x000000000040077e <+8>: mov QWORD PTR [rbp-0x8],rdi
0x0000000000400782 <+12>: mov DWORD PTR [rbp-0xc],esi
0x0000000000400785 <+15>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000400789 <+19>: mov rsi,rax
0x000000000040078c <+22>: mov edi,0x400974
0x0000000000400791 <+27>: call 0x400650 <strcmp@plt>
0x0000000000400796 <+32>: test eax,eax
0x0000000000400798 <+34>: je 0x4007aa <check_creds+52>
0x000000000040079a <+36>: cmp DWORD PTR [rbp-0xc],0xdeadc0de
0x00000000004007a1 <+43>: jne 0x4007aa <check_creds+52>
0x00000000004007a3 <+45>: mov eax,0x0
0x00000000004007a8 <+50>: jmp 0x4007af <check_creds+57>
0x00000000004007aa <+52>: mov eax,0x1
0x00000000004007af <+57>: leave
0x00000000004007b0 <+58>: ret
End of assembler dump.
gdb-peda$

Let's set some breakpoints on the function and proceed step by step. Thus, we can determine what data needs to be submitted to the input in order to pass the verification:
Code:
gdb-peda$ br check_creds
Breakpoint 1 at 0x40077a
gdb-peda$ c
Continuing.
gdb-peda$

Go back to the terminal where the script is running, press Enter to send the data. In a terminal where GDB is open, the debugger should interrupt execution at a breakpoint. Continue debugging to get the values you want.
 
Top