Copy Link
Add to Bookmark
Report

3 - Using GDB to develop exploits - A basic run through

This text provides some standard information on how to use GDB to debug an application during exploitation. By using a debugger it is possible to see exactly what is happening to an application during run-time, examining register and function values using common commands that help discover how to develop exploits.

eZine's profile picture
Published in 
open security
 · 22 Dec 2022

by c0ntex | c0ntexb[at]gmail.com
www.open-security.org

This document provides some useful basic commands to use with GDB during debug of applications for vulnerability development and troubleshooting.

From the GDB man page:

"The purpose of a debugger such as GDB is to allow you to see what is going on ‘‘inside’’ another program while it executes — or what another program was doing at the moment it crashed".

Launch GDB against either a binary, a core file or a Process ID

$ gdb ./vuln 
$ gdb ./vuln ./core
$ gdb -c ./core
$ gdb -silent `pidof vuln`

Set arguments for the application to execute with

(gdb) set args `perl -e 'print "A" x 50000'`

Set environment variables

(gdb) set env PATH=`perl -e 'print "A" x 50000'`

Set breakpoints

(gdb) b main				// Breaks at main() 
Breakpoint 1 at 0x8048fd9: file vuln.c, line 627.

(gdb) break strcpy // Breaks at strcpy()
Breakpoint 2 at 0x42079dd4

(gdb) break vuln.c:vuln_func

(gdb) rbreak ^vuln[_]func$

List defined breakpoints

(gdb) info b 
Num Type Disp Enb Address What
1 breakpoint keep y 0x08048fd9 in main at vuln.c:627

Run the binary

(gdb) run 
Starting program: /vuln/vuln `perl -e 'print "A" x 1000'`

Breakpoint 3, main (argc=2, argv=0xbfffee54) at vuln.c:627
627 CONSTRUCTGLOBALS();
(gdb)

Follow process forking

(gdb) set follow-fork-mode {parent, child, ask}

Show register addresses

(gdb) i r 
eax 0x49488fa8 1229492136
ecx 0x8074e68 134696552
edx 0x42131300 1108546304
ebx 0x42130a14 1108544020
esp 0xbfffc190 0xbfffc190
ebp 0xbfffc1f8 0xbfffc1f8
esi 0x41414140 1094795584
edi 0x8074e70 134696560
eip 0x420744b0 0x420744b0

Show function dissasembly

(gdb) disas 
Dump of assembler code for function main:
0x08048715 <main+0>: push %ebp
0x08048716 <main+1>: mov %esp,%ebp
0x08048718 <main+3>: sub $0x68,%esp
0x0804871b <main+6>: and $0xfffffff0,%esp

Show stored values on the stack

(gdb) print $esp 
$1 = (void *) 0xbfffc190

(gdb) x/5x $esp-10 // Hex
0xbfffedf6: 0xee084000 0x9442bfff 0x0a140805 0x53604213
0xbfffee06: 0xee284001

(gdb) x/5s $esp-10 //String
0xbfffedf6: ""
0xbfffedf7: "@\b???B\224\005\b\024\n\023B`S\001@(???tU\001B\002"
0xbfffee12: ""
0xbfffee13: ""
0xbfffee14: "T???`???,X\001@\002"

(gdb) x/5d $esp-10 //Decimal
0xbfffedf6: -301449216 -1807564801 169084933 1398817299
0xbfffee06: -299352063

(gdb) x/5i $esp-10 //Instructions
0xbfffedf6: add %al,0x8(%eax)
0xbfffedf9: out %al,(%dx)
0xbfffedfa: (bad)
0xbfffedfb: mov $0x8059442,%edi
0xbfffee00: adc $0xa,%al

(gdb) set $esp = 0
(gdb) print $esp
$3 = (void *) 0x0

Show where in the source file we are

(gdb) list 
622 int argc;
623 char *argv[];
624 {
625 int r;
626
627 CONSTRUCTGLOBALS();
628 p = checkid(argc, argv);
629 DESTROYGLOBALS();
630 strcpy(id_d, p);
631 while(1) {

Show where execution is

(gdb) where 
#0 main (argc=2, argv=0xbfff2764) at vuln.c:627
#1 0x42015574 in __libc_start_main () from /lib/tls/libc.so.6
(gdb)

Continue executing

(gdb) c				//Resume code execution 
Continuing.

Breakpoint 2, 0x42079dd4 in strcpy () from /lib/tls/libc.so.6
(gdb) s //Step into next function
Single stepping until exit from function vuln1,
which has no line number information.
check_vuln () at vuln1.c:259
259 whoUID = (u_id ? sys_UID_secret :
(gdb) s
309 usrIDnum = numIDnum = 0;
(gdb) c //Continue again
Continuing.

Breakpoint 2, 0x42079dd4 in strcpy () from /lib/tls/libc.so.6
(gdb) c //Continue again

Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

Show last frame on the stack

(gdb) where 1 
#0 0x41414141 in ?? ()
(More stack frames follow...)

Show failing frame info

(gdb) info frame 0 
Stack frame at 0xbfff3588:
eip = 0x41414141; saved eip 0x80530c2
called by frame at 0xbfff35c8
Arglist at 0xbfff3588, args:
Locals at 0xbfff3588, Previous frame's sp in esp
Saved registers:
ebp at 0xbfff3588, eip at 0xbfff358c

Show values in some useful registers

(gdb) x/x $eip 
0x41414141: Cannot access memory at address 0x41414141
(gdb) x/x $ebp
0xbfff3588: 0xbfff35c8
(gdb) x/x $esp
0xbfff354c: 0x08053309

Disassemble strcpy function

(gdb) disas strcpy 
Dump of assembler code for function strcpy:
0x42079dd0 <strcpy+0>: push %ebp
0x42079dd1 <strcpy+1>: mov %esp,%ebp
0x42079dd3 <strcpy+3>: push %esi
0x42079dd4 <strcpy+4>: mov 0x8(%ebp),%esi
0x42079dd7 <strcpy+7>: mov 0xc(%ebp),%edx
0x42079dda <strcpy+10>: mov %esi,%eax
0x42079ddc <strcpy+12>: sub %edx,%eax
0x42079dde <strcpy+14>: lea 0xffffffff(%eax),%ecx
0x42079de1 <strcpy+17>: jmp 0x42079df0 <strcpy+32>
0x42079de3 <strcpy+19>: nop
0x42079de4 <strcpy+20>: nop
0x42079dfb <strcpy+43>: mov %esi,%eax
0x42079dfd <strcpy+45>: pop %esi
0x42079dfe <strcpy+46>: pop %ebp
0x42079dff <strcpy+47>: ret
End of assembler dump.

Show content pointed to by a pointer

0x08054e2c in blah (p=0x41414141 <Address 0x41414141 out of bounds>) at vuln.c:284 
284 for (; *p; INCSTR(p))
(gdb) x/x p
0x41414141: Cannot access memory at address 0x41414141

Display executable sections

(gdb) main info sec 
Exec file:
`/root/vuln', file type elf32-i386.
0x080480f4->0x08048107 at 0x000000f4: .interp ALLOC LOAD READONLY DATA HAS_CONTENTS
0x08048108->0x08048128 at 0x00000108: .note.ABI-tag ALLOC LOAD READONLY DATA HAS_CONTENTS
0x08048128->0x080482c4 at 0x00000128: .hash ALLOC LOAD READONLY DATA HAS_CONTENTS
0x080482c4->0x080486c4 at 0x000002c4: .dynsym ALLOC LOAD READONLY DATA HAS_CONTENTS
0x080486c4->0x080488ce at 0x000006c4: .dynstr ALLOC LOAD READONLY DATA HAS_CONTENTS
0x080488ce->0x0804894e at 0x000008ce: .gnu.version ALLOC LOAD READONLY DATA HAS_CONTENTS
0x08048950->0x08048990 at 0x00000950: .gnu.version_r ALLOC LOAD READONLY DATA HAS_CONTENTS
0x08048990->0x080489b8 at 0x00000990: .rel.dyn ALLOC LOAD READONLY DATA HAS_CONTENTS
0x080489b8->0x08048b78 at 0x000009b8: .rel.plt ALLOC LOAD READONLY DATA HAS_CONTENTS
0x08048b78->0x08048b8f at 0x00000b78: .init ALLOC LOAD READONLY CODE HAS_CONTENTS
0x08048b90->0x08048f20 at 0x00000b90: .plt ALLOC LOAD READONLY CODE HAS_CONTENTS
0x08048f20->0x080594c0 at 0x00000f20: .text ALLOC LOAD READONLY CODE HAS_CONTENTS
0x080594c0->0x080594db at 0x000114c0: .fini ALLOC LOAD READONLY CODE HAS_CONTENTS
0x080594e0->0x0805f2e9 at 0x000114e0: .rodata ALLOC LOAD READONLY DATA HAS_CONTENTS
0x0805f2ec->0x0805f2f0 at 0x000172ec: .eh_frame ALLOC LOAD READONLY DATA HAS_CONTENTS
0x08060000->0x0806015c at 0x00018000: .data ALLOC LOAD DATA HAS_CONTENTS
0x0806015c->0x08060224 at 0x0001815c: .dynamic ALLOC LOAD DATA HAS_CONTENTS
0x08060224->0x0806022c at 0x00018224: .ctors ALLOC LOAD DATA HAS_CONTENTS
0x0806022c->0x08060234 at 0x0001822c: .dtors ALLOC LOAD DATA HAS_CONTENTS
0x08060234->0x08060238 at 0x00018234: .jcr ALLOC LOAD DATA HAS_CONTENTS
0x08060238->0x08060328 at 0x00018238: .got ALLOC LOAD DATA HAS_CONTENTS
0x08060340->0x08072e18 at 0x00018340: .bss ALLOC
0x00000000->0x00000462 at 0x00018340: .comment READONLY HAS_CONTENTS
0x00000000->0x00000258 at 0x000187a8: .debug_aranges READONLY HAS_CONTENTS
0x00000000->0x000006bf at 0x00018a00: .debug_pubnames READONLY HAS_CONTENTS
0x00000000->0x000448b3 at 0x000190bf: .debug_info READONLY HAS_CONTENTS
0x00000000->0x0000386e at 0x0005d972: .debug_abbrev READONLY HAS_CONTENTS
0x00000000->0x000049d8 at 0x000611e0: .debug_line READONLY HAS_CONTENTS
0x00000000->0x00001640 at 0x00065bb8: .debug_frame READONLY HAS_CONTENTS
0x00000000->0x00004d32 at 0x000671f8: .debug_str READONLY HAS_CONTENTS
0x00000000->0x000006a8 at 0x0006bf2a: .debug_ranges READONLY HAS_CONTENTS

Print data in the .plt section

(gdb) x/20x 0x08048b84 
0x8048b84 <_init+24>: 0x423c35ff 0x25ff0806 0x08064240 0x00000000
0x8048b94 <mkdir>: 0x424425ff 0x00680806 0xe9000000 0xffffffe0
0x8048ba4 <chown>: 0x424825ff 0x08680806 0xe9000000 0xffffffd0
0x8048bb4 <strchr>: 0x424c25ff 0x10680806 0xe9000000 0xffffffc0
0x8048bc4 <write>: 0x425025ff 0x18680806 0xe9000000 0xffffffb0

Print string values in the .bbs section

(gdb) x/5s 0x08060340+11000 
0x8062e38 <G+10968>: 'A' <repeats 200 times>...
0x8062f00 <G+11168>: 'A' <repeats 200 times>...
0x8062fc8 <G+11368>: 'A' <repeats 200 times>...
0x8063090 <G+11568>: 'A' <repeats 200 times>...
0x8063158 <G+11768>: 'A' <repeats 200 times>...
(gdb) x/5x 0x08072e18
0x8072e18: 0x41414141 0x41414141 0x41414141 0x41414141
0x8072e28: 0x41414141

Print the address for library system call

(gdb) x/x strcpy 
0x42079da0 <strcpy>: 0x56e58955
(gdb) x/x system
0x42041e50 <system>: 0x83e58955
(gdb) x/x printf
0x42052390 <printf>: 0x83e58955
(gdb) x/x exit
0x4202b0f0 <exit>: 0x57e58955

Finding shellcode location at +600 from $esp

(gdb) x/100x $esp+600 
0xbfff38c4: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfff38d4: 0x00000000 0x36690000 0x2f003638 0x746f6f72
0xbfff38e4: 0x7a6e752f 0x352d7069 0x2f31352e 0x697a6e75
0xbfff38f4: 0x41410070 0x41414141 0x41414141 0x41414141
0xbfff3904: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfff3914: 0x41414141 0x41414141 0x41414141 0x41414141
0xbfff3924: 0x41414141 0x41414141 0x41414141 0x41414141

Finding opcode values at -10 offset of $esp

(gdb) x/20bx $esp-10 
0xbfff2fc2: 0x06 0x08 0xc0 0xc5 0x05 0x08 0xec 0xc5
0xbfff2fca: 0x05 0x08 0x09 0x33 0x05 0x08 0x60 0x03
0xbfff2fd2: 0x06 0x08 0x18 0x0c

Return address (0xbfffc12f) alignment is off

(gdb) x/100x $esp-600 
0xbfff38c4: 0x00000000 0x00000000 0x00000000 0x00000000
0xbfff38d4: 0x90900070 0x90909090 0x90909090 0x90909090
0xbfff38e4: 0x90900090 0x90909090 0x90909090 0x90909090
0xbfff38f4: 0x90900090 0x90909090 0x90909090 0x90909090
0xbfff3904: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfff3914: 0x90909090 0x90909090 0x90909090 0x90909090
0xbfff3924: 0x2fbfffc1 0x00000000 0x00000000 0x00000000

(gdb) info sources
Source files for which symbols have been read in:

a=blah.c

Source files for which symbols will be read in on demand:


(gdb) info functions
All defined functions:

File blah.c: 
int attach_trc(int, pid_t);
void banner(void);
int detach_trc(int, pid_t);
int main(int, char **);
int show_trc(int, struct user_regs_struct);

Non-debugging symbols:
0x080483c0 _init
0x08048488 _start
0x080484ac call_gmon_start
0x080484d0 __do_global_dtors_aux
0x08048504 frame_dummy
0x080488d0 __libc_csu_init
0x08048924 __libc_csu_fini
0x08048968 __do_global_ctors_aux
0x0804898c _fini


(gdb) info file
Symbols from "/tmp/blah".
Local exec file:
`/tmp/blah', file type elf32-i386.
Entry point: 0x8048488
0x08048114 - 0x08048127 is .interp
0x08048128 - 0x08048148 is .note.ABI-tag
0x08048148 - 0x08048198 is .hash
0x08048198 - 0x08048288 is .dynsym
0x08048288 - 0x08048322 is .dynstr
0x08048322 - 0x08048340 is .gnu.version
0x08048340 - 0x08048360 is .gnu.version_r
0x08048360 - 0x08048370 is .rel.dyn
0x08048370 - 0x080483c0 is .rel.plt
0x080483c0 - 0x080483d7 is .init
0x080483d8 - 0x08048488 is .plt
0x08048488 - 0x0804898c is .text
0x0804898c - 0x080489a6 is .fini
0x080489a8 - 0x08048c36 is .rodata
0x08048c38 - 0x08048c3c is .eh_frame
0x08049c3c - 0x08049c44 is .ctors
0x08049c44 - 0x08049c4c is .dtors
0x08049c4c - 0x08049c50 is .jcr
0x08049c50 - 0x08049d18 is .dynamic
0x08049d18 - 0x08049d1c is .got
0x08049d1c - 0x08049d50 is .got.plt
0x08049d50 - 0x08049d5c is .data
0x08049d5c - 0x08049d64 is .bss

EOF

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT