Converting all those bytes and sending all those payloads in CTFs are a real pain in the ass. Using the pwntools library in Python can be a solution.
It provides numerous useful functions that will do some dirty work for you and free up some coffee time.


Connection

Most CTF or wargame pwnable challenges provide us a remote server to pwn and pwntools gives us the basic function of connecting to sockets.

ex)

nc: p = remote("0.0.0.0", 8888)
ssh: p = ssh("user", "0.0.0.0", port=8888, password="apple")
local: p = process("./file")

Voila! You have just connected to a remote server.
Note: ip, username, and file path is string while port is integer.


Interaction

Interaction here means the user using the shell itself. Normally, this function is used at the very last to view the flag after taking the shell.

p.interactive()

Note: some challenges in ssh might require the pwner to load the shell by himself. In this case, refer to the below function.

p.run("/bin/sh")

Hex Conversion

These functions are meant for preventing confusion when entering memory addresses in the little endian order.

ex)

p32(0x12345678) = \x78\x56\x34\x12
p32(0x12345678, endian='big')= \x12\x34\x56\x78
p64(0x12345678) = \x00\x00\x00\x00\x78\x56\x34\x12
p64(0x12345678, endian='big') = \x00\x00\x00\x00\x78\x56\x34\x12
u32("\x78\x56\x34\x12") = 305419896 (0x12345678)
u32("\x78\x56\x34\x12", endian='big') = 2018915346 (0x78563412)
u64("\x00\x00\x00\x00\x78\x56\x34\x12") = 305419896 (0x12345678)
u64("\x00\x00\x00\x00\x78\x56\x34\x12", endian='big') = 2018915346 (0x78563412)

Receiving & Sending

These functions are the very reason pwners use pwntools.
They allow us to receive strings that the server gives and send the whole payload.

recv(int): receive until the int size
recvline(): receive a line
recvuntil("test"): receive until the string "test"
send("test"): send "test"
sendline("test"): send "test" line(equals to pressing enter)

"time.c" is an example challenge of using short time interval:

#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[]){
	srand(time(NULL));
	int passcode = rand();
	int input;
	alarm(1);
	printf("Passcode : %d\n", passcode);
	scanf("%d",&input);
	if(passcode == input) printf("you're fast kiddo\n");
	else printf("too slow boi\n");
	return 0;
}
time.c

Even though the program directly provides us the random passcode, we can't enter it in a second.
Utilizing pwntools, we can easily write the solution code:

from pwn import *

p = process("./time")
p.recvuntil("Passcode : ")
passcode = p.recv(2048)
p.sendline(passcode)
print p.recv(2048)
time.py

The output:

pywchung@ubuntu:~/Desktop$ python solve.py
[+] Starting local process './time': pid 31873
[*] Process './time' stopped with exit code 0 (pid 31873)
you're fast kiddo

To be continued in Part 2