Leveraging CVE-2015-7547 for ASLR
Bypass & RCE
Gal De Leon & Nadav Markus
1
Introduction
• Vulnerability in glibc
• Discovered by Google, patched at 16-feb-2016
• Released crash-poc
• This presentation is about exploitation strategy
3
getaddrinfo()
• A function used to resolve a hostname to IP-address(es)
• OUT-addressinfo* is later used for connect() or bind()
• Performs DNS queries
• Stack-overflow vulnerability was found, handling DNS-replies
4
“Given node and service, which identify an Internet host and a
service, getaddrinfo() returns one or more addrinfo structures, each
of which contains an Internet address that can be specified in a call
to bind(2) or connect(2).”
getaddrinfo()
• struct addrinfo -> ai_family
• AF_INET, AF_INET6, AF_UNSPEC
• AF_UNSPEC indicates any address family is valid, IPv4 or IPv6
• IPv4=A, IPv6=AAAA
• This is the common usecase
5
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res);
The Bug
6
Victim Attacker
dns-query A & AAAA over UDP
calls glibc’s getaddrinfo()
alloca(2048)
_nss_dns_gethostbyname4_r(..) {
…
host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
The Bug
7
Victim Attacker
dns-reply FLAGS=TRUNCATED, ‘xAA’*2500
_alloca() buffer isn’t sufficient
malloc(MAXPACKET) instead
(MAXPACKET=0x10000) “…If the answer section of the response is truncated and if the
requester supports TCP, it SHOULD try the query again using
TCP.” (RFC-DNS)
The Bug
8
Victim Attacker
dns-query A & AAAA over TCP
The Bug
9
Victim Attacker
reuses the ‘malloced’ buffer
‘A’ valid dns-reply
The Bug
10
Victim Attacker
‘AAAA’ malformed dns-reply
Mismatch between the stack and the heap buffer!
If ‘AAAA’ dns-response’s size is greater than 2048,
we smash the stack!
‘A’ valid dns-reply
Reply Arbitrary DNS
• Assume attacker can answer arbitrary DNS requests
• Acquiring the domain
• Local Arp Poisoning
• Any other way ..
11
DEP & ASLR
• Unable to exploit reliably without bypassing DEP & ASLR
• We can set RIP to anywhere, but where to?
• How to ROP?
Overflow
.
.
.
RET ; pop, jmp
original
buffer
retaddress
ASLR Bypass Techniques
• Non PIE executables
• Read memory vulnerability
• Spray (without DEP)
• Can’t get reliable address at 64 bit..
• How about guessing?
13
fork()
• Standard way of creating processes in UNIX
• Child process inherits:
• Memory Layout (includes loaded modules )
• Registers state
• Stack
14
pid = fork();
if (0 < pid) {
/* Parent code goes here... */
} else if (0 == pid) {
/* Child code goes here... */
}
…
fork – the kernel view
15
/*
* Ok, this is the main fork-routine.
*
* It copies the process, and if successful kick-starts
* it and waits for it to finish using the VM if required.
*/
long do_fork(unsigned long clone_flags,
unsigned long stack_start,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)
…
p = copy_process(clone_flags, stack_start, stack_size, child_tidptr, NULL, trace);
/kernel/fork.c
fork – the kernel view
16
/*
* This creates a new process as a copy of the old one,
* but does not actually start it yet.
*
* It copies the registers, and all the appropriate
* parts of the process environment (as per the clone
* flags). The actual kick-off is left to the caller.
*/
static struct task_struct *copy_process(unsigned long clone_flags,
unsigned long stack_start,
unsigned long stack_size,
int __user *child_tidptr,
struct pid *pid,
int trace)
…
retval = copy_mm(clone_flags, p);
/kerne/fork.c
fork – the kernel view
17
/*
* Allocate a new mm structure and copy contents from the
* mm structure of the passed in task structure.
*/
struct mm_struct *dup_mm(struct task_struct *tsk)
{
...
memcpy(mm, oldmm, sizeof(*mm));
...
exec vs fork
• exec allows us to change the current executing image in a process
• There are different handlers for different file formats – the kernel chooses the correct one from the binfmt
handlers:
18
static int exec_binprm(struct linux_binprm *bprm)
{
...
ret = search_binary_handler(bprm);
exec vs fork
19
• /fs/binfmt_elf.c contains the logic for executing ELF files
• Core function that set ups exec for ELF – load_elf_binary
• Specifically, we are interested in how randomization is implemented, and what get randomized
• Key functions in randomization:
• randomize_stack_top – top of the stack
• arch_randomize_brk – heap
• mmap (not in this specific file, but used for each loaded shared object), and elf_map (which invokes
the same functionality, but for the main executable in case of PIE from the kernel)
• We will see later how some of these randomization features affect our exploit..
Attacker
10.1.1.137
Victim
Trigger fork()
20
Attacker
10.1.1.137
Victimfork()
child-process (PID=3312):
21
Attacker
10.1.1.137
Victimfork()
child-process (PID=3312):
1212100C CALL getaddrinfo
12121012 test eax, eax
…
dns-queries
22
Attacker
10.1.1.137
Victimfork()
child-process (PID=3312):
1212100C CALL getaddrinfo
OVERFLOW RIP=0x01010101
INVALID-OPCODE
CRASH!
12121012 test eax, eax
…
malicious dns-replies host @ 10.1.1.137
23
Attacker
10.1.1.137
Victim
Trigger fork()
24
Attacker
10.1.1.137
Victimfork()
child-process (PID=3313):
1212100C CALL getaddrinfo
12121012 test eax, eax
…
dns-queries
25
Attacker
10.1.1.137
Victimfork()
child-process (PID=3313):
1212100C CALL getaddrinfo
OVERFLOW RIP=0x12121012
12121012 test eax, eax
…
malicious dns-replies host @ 10.1.1.137
26
Attacker
10.1.1.137
Victimfork()
child-process (PID=3313):
1212100C CALL getaddrinfo
OVERFLOW RIP=0x12121012
12121012 test eax, eax
…
connect()
TCP syn 10.1.1.137
0x12121012
is the correct
address!
27
Exploit Strategy
• We can enumerate all possible addresses
• ~2 ^ 64
• Not feasible
28
Byte by Byte Approach
• Instead of overwriting RIP entirely, we can overwrite just a portion
of it
• Remaining bytes are of the original address
29
CALL getaddrinfo()
Original RIP = 0x12121012 DNS request-response (malformed)
AAAAA..AAA../x00
Attacker
Overwritten RIP =
0x12121000
12 10 12 12 00 00 00 00
00 10 12 12 00 00 00 00
Original RIP
Overwritten RIP
LSB MSB
Byte by Byte Approach
8 * 256 
30
Return Address Sent Buffer Response?
0x0000000012121000 AAA...0x00 NO
0x0000000012121001 AAA...0x01 NO
0x00000000121210…. … NO
0x0000000012121012 AAA...0x12 YES
0x0000000012120012 AAA…0x12 0x00 NO
0x0000000012120112 AAA…0x12 0x01 NO
0x000000001212….12 … NO
0x0000000012121012 AAA…0x12 0x10 YES
…. …
Finding Potentially Exploitable Applications
• fork() && getaddrinfo()
• Using the correct flow
• Indication of crash
• http://codesearch.debian.net
• Indexes source code of ~18,000 packages
• ~1,300 potential exploitable apps
31
Finding Potentially Exploitable Applications
…
914 xtrace
915 openbgpd
916 balsa
917 tinyproxy
918 powerman
919 mahimahi
920 pcs
921 eric
922 ruby-pg
923 nut
924 gnulib
…
32
child process – fork()
tinyproxy
33
Tinyproxy
CONNECT www.somewhere.com
user
dns-query
A & AAAA somewhere.com
DNS server
HTTP request (tcp-syn 80)
www.somewhere.com
1. CONNECT is used to trigger fork() remotely
2. http-request is used as an indication of success
Game Over?
34
Is RIP Really Controlled?
• So let’s enumerate getaddrinfo’s return address
• But we crash 
• Local-variables are overridden
• Some are pointers ..
• So let’s leak them 
35
…
Stack buffer
…
…
…
Local variable
Local variable
Local variable
Local variable
…
Frame pointer
Return address
Segfault (1st)
• RBX originally points the stack
• We can leak this address too!
• Address pointed by RBX only has to be writeable
• Flow is not effected
36
Leak RBX (arbitrary stack address)
(/proc/PID/maps)
limit base length
0x7ffd07882000 0x7ffd078a3000 0x21000 0x0 [stack]
0x7ffd079f0000 0x7ffd079f2000 0x2000 0x0 [vvar]
• We cannot leak lower 12 bits, since anything will do 
• Stack size is greater than 0x1000
37
AA A2 88 07 FD 7F 00 00
Stack
0x7ffd078a3000
0x7ffd07882000
Segfault (2nd)
• RDI is controlled (hostbuffer.buf)
• R14 is the original alloca() buffer
• free(RDI) if not equal
• Abort crash
• We don’t get to overwrite RIP ..
• How to predict R14 value?
38
...
host_buffer.buf = orig_host_buffer =
(querybuf *) alloca (2048);
... /* might malloc host_buffer.buf */
if (host_buffer.buf !=
orig_host_buffer)
free (host_buffer.buf);
...
return status;
Stack is Identical for Different fork()s
39
tinyproxy
daemon
orig_host_buffer
= alloca(2048);
orig_host_buffer
@ 0x7ffd078a3080
child
orig_host_buffer
= alloca(2048);
orig_host_buffer
@ 0x7ffd078a3080
child
orig_host_buffer
= alloca(2048);
orig_host_buffer
@ 0x7ffd078a3080
child … … …
fork()
fork()
fork()
Precise Pointers
40
• Stack is identical in different forks
• host_buffer.buf PTR is the same
in all executions
• Use constant offset from
stack base!
...
host_buffer.buf = orig_host_buffer =
(querybuf *) alloca (2048);
... /* might malloc host_buffer.buf */
if (host_buffer.buf !=
orig_host_buffer)
free (host_buffer.buf);
...
return status;
Leak Stack Base
• Use 1th crash (mov [rbx], sil)
• Use leaked arbitrary stack address as a starting point
• Add 0x1000 offset at a time
41
rbx Sent Buffer Response?
0x00007fffed000000 AAA...0x00 0x00 0x00 0xed 0xff 0x7f YES
0x00007fffed001000 AAA...0x00 0x10 0x00 0xed 0xff 0x7f YES
0x00007fffed002000 AAA...0x00 0x20 0x00 0xed 0xff 0x7f YES
0x00007fffed003000 AAA...0x00 0x30 0x00 0xed 0xff 0x7f YES
0x00007fffed004000 AAA...0x00 0x40 0x00 0xed 0xff 0x7f YES
0x00007fffed005000 AAA...0x00 0x50 0x00 0xed 0xff 0x7f YES
0x00007fffed006000 AAA...0x00 0x60 0x00 0xed 0xff 0x7f YES
0x00007fffed007000 AAA...0x00 0x70 0x00 0xed 0xff 0x7f YES
0x00007fffed008000 AAA...0x00 0x80 0x00 0xed 0xff 0x7f NO
Game Over?
42
0xaa0000 Stack base
… …
0xa9fc00 (-0x400) orig_host_buffer
… …
… …
… …
0xa9f500 (-0xb00) Local variable
0xa9f4f8 (-0xb08) Local variable
…
0xa9f400 (-0xc00) Frame pointer
0xa9f3f8 (-0xc08) Return address
Leaked =>
0x400 is constant offset =>
Offset from Stack-Base is Constant?
43
/arch/x86/kernel/process.c
unsigned long arch_align_stack(unsigned long sp)
{
if (!(current->personality & ADDR_NO_RANDOMIZE)
&& randomize_va_space)
sp -= get_random_int() % 8192;
return sp & ~0xf;
}
Leak libc base (for fun & gadgets)
44
• Gain control over RIP (leak all local variables in the way … )
• Leak getaddrinfo()’s return address
• Get libc’s base address
• Constant offset from ret address!
• ROP (ret2libc)
glibc module
(+0xaabbcc ) return address =>
( 0 ) glibc start =>
libc Version?
• Different offset for different versions
• We don’t know what the version is
• So we just enumerate 
45
glibc
module
(+0xaabbcc ) return address =>
( 0 ) glibc start =>
glibc
module(+0x998877) return address =>
( 0 ) glibc start =>
... … …
Complete Exploitation Flow
• Leak arbitrary stack pointer ( 1st segfault => rbx)
• Leak stack base
• Leak random stack offset (for precise stack variables)
• Leak getaddrinfo()’s return address
• Enumerate ret2libc offsets, until successfully exploited
46
Demo
47
Questions?
48

Bypassing ASLR Exploiting CVE 2015-7545

  • 1.
    Leveraging CVE-2015-7547 forASLR Bypass & RCE Gal De Leon & Nadav Markus 1
  • 2.
    Introduction • Vulnerability inglibc • Discovered by Google, patched at 16-feb-2016 • Released crash-poc • This presentation is about exploitation strategy 3
  • 3.
    getaddrinfo() • A functionused to resolve a hostname to IP-address(es) • OUT-addressinfo* is later used for connect() or bind() • Performs DNS queries • Stack-overflow vulnerability was found, handling DNS-replies 4 “Given node and service, which identify an Internet host and a service, getaddrinfo() returns one or more addrinfo structures, each of which contains an Internet address that can be specified in a call to bind(2) or connect(2).”
  • 4.
    getaddrinfo() • struct addrinfo-> ai_family • AF_INET, AF_INET6, AF_UNSPEC • AF_UNSPEC indicates any address family is valid, IPv4 or IPv6 • IPv4=A, IPv6=AAAA • This is the common usecase 5 int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
  • 5.
    The Bug 6 Victim Attacker dns-queryA & AAAA over UDP calls glibc’s getaddrinfo() alloca(2048) _nss_dns_gethostbyname4_r(..) { … host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048);
  • 6.
    The Bug 7 Victim Attacker dns-replyFLAGS=TRUNCATED, ‘xAA’*2500 _alloca() buffer isn’t sufficient malloc(MAXPACKET) instead (MAXPACKET=0x10000) “…If the answer section of the response is truncated and if the requester supports TCP, it SHOULD try the query again using TCP.” (RFC-DNS)
  • 7.
  • 8.
    The Bug 9 Victim Attacker reusesthe ‘malloced’ buffer ‘A’ valid dns-reply
  • 9.
    The Bug 10 Victim Attacker ‘AAAA’malformed dns-reply Mismatch between the stack and the heap buffer! If ‘AAAA’ dns-response’s size is greater than 2048, we smash the stack! ‘A’ valid dns-reply
  • 10.
    Reply Arbitrary DNS •Assume attacker can answer arbitrary DNS requests • Acquiring the domain • Local Arp Poisoning • Any other way .. 11
  • 11.
    DEP & ASLR •Unable to exploit reliably without bypassing DEP & ASLR • We can set RIP to anywhere, but where to? • How to ROP? Overflow . . . RET ; pop, jmp original buffer retaddress
  • 12.
    ASLR Bypass Techniques •Non PIE executables • Read memory vulnerability • Spray (without DEP) • Can’t get reliable address at 64 bit.. • How about guessing? 13
  • 13.
    fork() • Standard wayof creating processes in UNIX • Child process inherits: • Memory Layout (includes loaded modules ) • Registers state • Stack 14 pid = fork(); if (0 < pid) { /* Parent code goes here... */ } else if (0 == pid) { /* Child code goes here... */ } …
  • 14.
    fork – thekernel view 15 /* * Ok, this is the main fork-routine. * * It copies the process, and if successful kick-starts * it and waits for it to finish using the VM if required. */ long do_fork(unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) … p = copy_process(clone_flags, stack_start, stack_size, child_tidptr, NULL, trace); /kernel/fork.c
  • 15.
    fork – thekernel view 16 /* * This creates a new process as a copy of the old one, * but does not actually start it yet. * * It copies the registers, and all the appropriate * parts of the process environment (as per the clone * flags). The actual kick-off is left to the caller. */ static struct task_struct *copy_process(unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size, int __user *child_tidptr, struct pid *pid, int trace) … retval = copy_mm(clone_flags, p); /kerne/fork.c
  • 16.
    fork – thekernel view 17 /* * Allocate a new mm structure and copy contents from the * mm structure of the passed in task structure. */ struct mm_struct *dup_mm(struct task_struct *tsk) { ... memcpy(mm, oldmm, sizeof(*mm)); ...
  • 17.
    exec vs fork •exec allows us to change the current executing image in a process • There are different handlers for different file formats – the kernel chooses the correct one from the binfmt handlers: 18 static int exec_binprm(struct linux_binprm *bprm) { ... ret = search_binary_handler(bprm);
  • 18.
    exec vs fork 19 •/fs/binfmt_elf.c contains the logic for executing ELF files • Core function that set ups exec for ELF – load_elf_binary • Specifically, we are interested in how randomization is implemented, and what get randomized • Key functions in randomization: • randomize_stack_top – top of the stack • arch_randomize_brk – heap • mmap (not in this specific file, but used for each loaded shared object), and elf_map (which invokes the same functionality, but for the main executable in case of PIE from the kernel) • We will see later how some of these randomization features affect our exploit..
  • 19.
  • 20.
  • 21.
    Attacker 10.1.1.137 Victimfork() child-process (PID=3312): 1212100C CALLgetaddrinfo 12121012 test eax, eax … dns-queries 22
  • 22.
    Attacker 10.1.1.137 Victimfork() child-process (PID=3312): 1212100C CALLgetaddrinfo OVERFLOW RIP=0x01010101 INVALID-OPCODE CRASH! 12121012 test eax, eax … malicious dns-replies host @ 10.1.1.137 23
  • 23.
  • 24.
    Attacker 10.1.1.137 Victimfork() child-process (PID=3313): 1212100C CALLgetaddrinfo 12121012 test eax, eax … dns-queries 25
  • 25.
    Attacker 10.1.1.137 Victimfork() child-process (PID=3313): 1212100C CALLgetaddrinfo OVERFLOW RIP=0x12121012 12121012 test eax, eax … malicious dns-replies host @ 10.1.1.137 26
  • 26.
    Attacker 10.1.1.137 Victimfork() child-process (PID=3313): 1212100C CALLgetaddrinfo OVERFLOW RIP=0x12121012 12121012 test eax, eax … connect() TCP syn 10.1.1.137 0x12121012 is the correct address! 27
  • 27.
    Exploit Strategy • Wecan enumerate all possible addresses • ~2 ^ 64 • Not feasible 28
  • 28.
    Byte by ByteApproach • Instead of overwriting RIP entirely, we can overwrite just a portion of it • Remaining bytes are of the original address 29 CALL getaddrinfo() Original RIP = 0x12121012 DNS request-response (malformed) AAAAA..AAA../x00 Attacker Overwritten RIP = 0x12121000 12 10 12 12 00 00 00 00 00 10 12 12 00 00 00 00 Original RIP Overwritten RIP LSB MSB
  • 29.
    Byte by ByteApproach 8 * 256  30 Return Address Sent Buffer Response? 0x0000000012121000 AAA...0x00 NO 0x0000000012121001 AAA...0x01 NO 0x00000000121210…. … NO 0x0000000012121012 AAA...0x12 YES 0x0000000012120012 AAA…0x12 0x00 NO 0x0000000012120112 AAA…0x12 0x01 NO 0x000000001212….12 … NO 0x0000000012121012 AAA…0x12 0x10 YES …. …
  • 30.
    Finding Potentially ExploitableApplications • fork() && getaddrinfo() • Using the correct flow • Indication of crash • http://codesearch.debian.net • Indexes source code of ~18,000 packages • ~1,300 potential exploitable apps 31
  • 31.
    Finding Potentially ExploitableApplications … 914 xtrace 915 openbgpd 916 balsa 917 tinyproxy 918 powerman 919 mahimahi 920 pcs 921 eric 922 ruby-pg 923 nut 924 gnulib … 32
  • 32.
    child process –fork() tinyproxy 33 Tinyproxy CONNECT www.somewhere.com user dns-query A & AAAA somewhere.com DNS server HTTP request (tcp-syn 80) www.somewhere.com 1. CONNECT is used to trigger fork() remotely 2. http-request is used as an indication of success
  • 33.
  • 34.
    Is RIP ReallyControlled? • So let’s enumerate getaddrinfo’s return address • But we crash  • Local-variables are overridden • Some are pointers .. • So let’s leak them  35 … Stack buffer … … … Local variable Local variable Local variable Local variable … Frame pointer Return address
  • 35.
    Segfault (1st) • RBXoriginally points the stack • We can leak this address too! • Address pointed by RBX only has to be writeable • Flow is not effected 36
  • 36.
    Leak RBX (arbitrarystack address) (/proc/PID/maps) limit base length 0x7ffd07882000 0x7ffd078a3000 0x21000 0x0 [stack] 0x7ffd079f0000 0x7ffd079f2000 0x2000 0x0 [vvar] • We cannot leak lower 12 bits, since anything will do  • Stack size is greater than 0x1000 37 AA A2 88 07 FD 7F 00 00 Stack 0x7ffd078a3000 0x7ffd07882000
  • 37.
    Segfault (2nd) • RDIis controlled (hostbuffer.buf) • R14 is the original alloca() buffer • free(RDI) if not equal • Abort crash • We don’t get to overwrite RIP .. • How to predict R14 value? 38 ... host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048); ... /* might malloc host_buffer.buf */ if (host_buffer.buf != orig_host_buffer) free (host_buffer.buf); ... return status;
  • 38.
    Stack is Identicalfor Different fork()s 39 tinyproxy daemon orig_host_buffer = alloca(2048); orig_host_buffer @ 0x7ffd078a3080 child orig_host_buffer = alloca(2048); orig_host_buffer @ 0x7ffd078a3080 child orig_host_buffer = alloca(2048); orig_host_buffer @ 0x7ffd078a3080 child … … … fork() fork() fork()
  • 39.
    Precise Pointers 40 • Stackis identical in different forks • host_buffer.buf PTR is the same in all executions • Use constant offset from stack base! ... host_buffer.buf = orig_host_buffer = (querybuf *) alloca (2048); ... /* might malloc host_buffer.buf */ if (host_buffer.buf != orig_host_buffer) free (host_buffer.buf); ... return status;
  • 40.
    Leak Stack Base •Use 1th crash (mov [rbx], sil) • Use leaked arbitrary stack address as a starting point • Add 0x1000 offset at a time 41 rbx Sent Buffer Response? 0x00007fffed000000 AAA...0x00 0x00 0x00 0xed 0xff 0x7f YES 0x00007fffed001000 AAA...0x00 0x10 0x00 0xed 0xff 0x7f YES 0x00007fffed002000 AAA...0x00 0x20 0x00 0xed 0xff 0x7f YES 0x00007fffed003000 AAA...0x00 0x30 0x00 0xed 0xff 0x7f YES 0x00007fffed004000 AAA...0x00 0x40 0x00 0xed 0xff 0x7f YES 0x00007fffed005000 AAA...0x00 0x50 0x00 0xed 0xff 0x7f YES 0x00007fffed006000 AAA...0x00 0x60 0x00 0xed 0xff 0x7f YES 0x00007fffed007000 AAA...0x00 0x70 0x00 0xed 0xff 0x7f YES 0x00007fffed008000 AAA...0x00 0x80 0x00 0xed 0xff 0x7f NO
  • 41.
    Game Over? 42 0xaa0000 Stackbase … … 0xa9fc00 (-0x400) orig_host_buffer … … … … … … 0xa9f500 (-0xb00) Local variable 0xa9f4f8 (-0xb08) Local variable … 0xa9f400 (-0xc00) Frame pointer 0xa9f3f8 (-0xc08) Return address Leaked => 0x400 is constant offset =>
  • 42.
    Offset from Stack-Baseis Constant? 43 /arch/x86/kernel/process.c unsigned long arch_align_stack(unsigned long sp) { if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) sp -= get_random_int() % 8192; return sp & ~0xf; }
  • 43.
    Leak libc base(for fun & gadgets) 44 • Gain control over RIP (leak all local variables in the way … ) • Leak getaddrinfo()’s return address • Get libc’s base address • Constant offset from ret address! • ROP (ret2libc) glibc module (+0xaabbcc ) return address => ( 0 ) glibc start =>
  • 44.
    libc Version? • Differentoffset for different versions • We don’t know what the version is • So we just enumerate  45 glibc module (+0xaabbcc ) return address => ( 0 ) glibc start => glibc module(+0x998877) return address => ( 0 ) glibc start => ... … …
  • 45.
    Complete Exploitation Flow •Leak arbitrary stack pointer ( 1st segfault => rbx) • Leak stack base • Leak random stack offset (for precise stack variables) • Leak getaddrinfo()’s return address • Enumerate ret2libc offsets, until successfully exploited 46
  • 46.
  • 47.