Take this gdb output for example:
(gdb) info proc mappings
process 3975
cmdline = '/mnt/hw6/rop-exploit'
cwd = '/mnt/hw6'
exe = '/mnt/hw6/rop-exploit'
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8049000 0x1000 0 /mnt/hw6/rop-exploit
0x8049000 0x804a000 0x1000 0 /mnt/hw6/rop-exploit
0x804a000 0x806b000 0x21000 0x804a000 [heap]
0xb7d51000 0xb7e84000 0x133000 0 /lib/libc-2.7.so
0xb7e84000 0xb7e85000 0x1000 0x133000 /lib/libc-2.7.so
0xb7e85000 0xb7e87000 0x2000 0x134000 /lib/libc-2.7.so
0xb7e87000 0xb7e8b000 0x4000 0xb7e87000
0xb7e8b000 0xb7fd4000 0x149000 0 /lib/tls/i686/cmov/libc-2.7.so
0xb7fd4000 0xb7fd5000 0x1000 0x149000 /lib/tls/i686/cmov/libc-2.7.so
0xb7fd5000 0xb7fd7000 0x2000 0x14a000 /lib/tls/i686/cmov/libc-2.7.so
0xb7fd7000 0xb7fda000 0x3000 0xb7fd7000
0xb7fda000 0xb7fdc000 0x2000 0 /lib/tls/i686/cmov/libdl-2.7.so
0xb7fdc000 0xb7fde000 0x2000 0x1000 /lib/tls/i686/cmov/libdl-2.7.so
0xb7fe1000 0xb7fe3000 0x2000 0xb7fe1000
0xb7fe3000 0xb7fe4000 0x1000 0xb7fe3000 [vdso]
0xb7fe4000 0xb7ffe000 0x1a000 0 /lib/ld-2.7.so
0xb7ffe000 0xb8000000 0x2000 0x19000 /lib/ld-2.7.so
0xbffeb000 0xc0000000 0x15000 0xbffeb000 [stack]
(gdb) list
13 }
14
15 int main(int argc, char** argv) {
16 void* libc = dlopen("/lib/libc-2.7.so", RTLD_NOW);
17 void* address = dlsym( libc, "__libc_init_first");
18 printf("Address of <__libc_init_first>: %p\n", address);
19 if(argc > 1) {
20 foo(argv[1]);
21 }
22 printf("Done.\n");
(gdb) x libc
0x804a020: 0xb7d51000
(gdb) print address
$4 = (void *) 0xb7d672a0
You can see that three libraries are dynamically linked with the binary. libc-2.7, libc2-7.so (from a different location, maybe this is done automatically) and libdl-2.7.so
I dont understand why there are two to three entries in this list per library, I want to know what is going on there, and why they are separate entries.
I dont have any assumptions what is going on there and I dont know how I can explain any of this.
Take the first linked library for example:
The first section I assume is the library itself, it has the ELF header so I am convinced that it truly is the libc I have linked.
When I peek into the second entry of /lib/libc-2.7-so I just get lots of NULL bytes, dont know whats going on here.
(gdb) x/100x 0xb7e84000
0xb7e84000: 0x00000000 0x00000000 0x00000000 0x00000000
0xb7e84010: 0x00000000 0x00000000 0x00000000 0x00000000
0xb7e84020: 0x00000000 0x00000000 0x00000000 0x00000000
When I peek into the third entry of /lib/libc-2.6.so I get addresses to instructions (gadgets or functions maybe).
(gdb) x/100x 0xb7e85000
0xb7e85000: 0x0000006f 0xb7e671dc 0xb7e671e0 0xb7e671e4
0xb7e85010: 0xb7e671e8 0xb7e671ec 0xb7e671f0 0xb7e671f4
0xb7e85020: 0xb7e671f8 0xb7e671ff 0xb7e67206 0xb7e6720e
This is the example output I get from one of the addresses, seems pretty convincing that this could be usable code.
(gdb) x/10i 0xb7e671e8
0xb7e671e8: push %edi
0xb7e671e9: add %dl,%fs:%gs:0x75(%eax,%ebp,2)
0xb7e671ef: add %al,0x72(%esi)
0xb7e671f2: imul $0x746153,(%eax),%eax
0xb7e671f8: push %ebx
0xb7e671f9: jne 0xb7e67269
0xb7e671fb: fs
0xb7e671fc: popa
0xb7e671fd: jns 0xb7e671ff
0xb7e671ff: dec %ebp
(gdb)
My questions are, what are these three sections doing each ? Why are they split up like that ? What happens in the area where no corresponding label exists but is still mapped ?
Related
I'm currently learning about C and trying to find out more about how memory in a stack works, and how gdb can be used to help.
Below is a code snippet of my problem:
bool thisEvaluatesToFalse(char* something) {
return false;
}
void main() {
char something[10];
puts("My plan is to input a specific string over 10 characters than will achieve my goal:");
gets(something);
if (thisEvaluatesToFalse(something)) {
puts("If this runs, its a success!");
}
}
The idea is, my success message will never run unless I exploit gets to input a something over 10 characters, causing an overflow that overwrites the return address of the function to where the success message is.
I understand I'm supposed to take a look at the assembly code with gdb and look out for an address, but I'm not exactly sure how to do this.
Could anyone guide me or show me an example? Thanks!
Try this, hope it helps you figure this out. Good luck!
Consider moving gets into thisEvaluatesToFalse to overwrite the return address pushed by main so the return from thisEvaluatesToFalse will return to the puts of success.
Like this:
#include <stdio.h>
unsigned int thisEvaluatesToFalse() {
char something[10];
gets(something);
return 0xdeadbeef;
}
int main() {
puts("My plan is to input a specific string over 10 characters than will achieve my goal:");
if (thisEvaluatesToFalse()) {
puts("If this runs, its a success!");
}
return 0;
}
Here are the highlights of working w/ gdb.
gcc main.c -fno-stack-protector -ggdb
gdb a.out
(gdb) disass main
0x0000000100003eeb <+27>: call 0x100003eb0 <thisEvaluatesToFalse>
0x0000000100003ef0 <+32>: cmp $0x0,%eax
0x0000000100003ef3 <+35>: je 0x100003f05 <main+53>
0x0000000100003ef9 <+41>: lea 0x94(%rip),%rdi # 0x100003f94
0x0000000100003f00 <+48>: call 0x100003f14
# ORIG RETURN ADDRESS IS 0x0000000100003ef0
# EXPLOIT RETURN ADDRESS FOR SUCCESS IS 0x0000000100003ef9
(gdb) break thisEvaluatesToFalse
(gdb) run
(gdb) x/16x $sp
0x7ff7bfeff930: 0x000c8060 0x00000001 0x00003ed0 0x00000001
0x7ff7bfeff940: 0xbfeff960 0x00007ff7 0x00003ef0 0x00000001
0x7ff7bfeff950: 0x00000013 0x00000000 0x000c8060 0x00000000
0x7ff7bfeff960: 0xbfeffa70 0x00007ff7 0x0001552e 0x00000001
# NOTICE THE VALUE AT 0x7ff7bfeff948 IS 0x00003ef0 (ORIG RETURN)
# NOTICE THE VALUE AT 0x7ff7bfeff94C IS 0x00000001 (ORIG RETURN)
(gdb) s
warning: this program uses gets(), which is unsafe.
1234567890AAAABBBBCCCCDDDD
(gdb) x/16x $sp
0x7ff7bfeff930: 0x000c8060 0x32310001 0x36353433 0x30393837
0x7ff7bfeff940: 0x41414141 0x42424242 0x43434343 0x44444444
0x7ff7bfeff950: 0x00000000 0x00000000 0x000c8060 0x00000000
0x7ff7bfeff960: 0xbfeffa70 0x00007ff7 0x0001552e 0x00000001
# NOTICE THE VALUE AT 0x7ff7bfeff948 IS 0x43434343 (LETTER C)
# NOTICE THE VALUE AT 0x7ff7bfeff94C IS 0x44444444 (LETTER D)
(gdb) set *0x7ff7bfeff948 = 0x00003ef9
(gdb) set *0x7ff7bfeff94C = 0x00000001
(gdb) x/16x $sp
0x7ff7bfeff930: 0x000c8060 0x32310001 0x36353433 0x30393837
0x7ff7bfeff940: 0x41414141 0x42424242 0x00003ef9 0x00000001
(gdb) s
main () at main.c:17
17 puts("If this runs, its a success!");
(gdb) s
If this runs, its a success!
19 return 0;
Leaving it up to you to figure out how to input values for gets that perform the actions that replace C and D with the values you need.
If you can choose a different approach, then instead of using gets for the overflow try using memcpy and copy more than 10 bytes. Same impact, the stack gets modified.
I am trying to create a chain of pointer addresses, with the first pointing to address of the next, and so on.
For example, char *a 's address is 0x1, char *b address is 0x2, char *x address is 0x3. I want to link a->b->c, so that my hope is to store value 0x2 into 0x1 memory address, value 0x3 into 0x2 memory address.
I have following codes:
#define PUT(p, val) (*(unsigned long *)(p) = (val))
#define SET_NEXT_PTR(p, ptr) (*(char**)(p) = (char*)((unsigned long)(ptr)))
void chain(char* bp){
char *first = mem_sbrk(size);
char *second =mem_sbrk(size);
PUT(first, (unsigned long)bp);
PUT(bp, *second);
}
When I run gdb, and exam those memory address. After call mem_sbrk for first and second.
(gdb) x /x first
0x7ffff661c020: 0x00000000
(gdb) x /x bp
0x7ffff661b020: 0x00000000
(gdb) x/x second
0x7ffff661d020: 0x00000000
After call PUT macro:
(gdb) x/x second
0x7ffff661d020: 0x00000000 0x00000000
(gdb) x /2x first
0x7ffff661c020: 0xf661b020 0x00007fff
(gdb) p first
0x7ffff661c020 " \260a\366\377\177"
(gdb) x /2x bp
0x7ffff661b020: 0xf661d020 0x00007fff
It seems working. But I wonder how can I convert those memory address to a pointer. Since entire memory address stores into 0x7ffff661d020 and 0x7ffff661d024. When I use p first, it returns a meaningless string.
Second question, in gdb when I call
(gdb) p &bp
(char **) 0x7fffffffe3e8
I wonder what is 0x7fffffffe3e8? I thought & is for getting memory address,I expect gdb shows
(void*) 0x7ffff661b020
Third question what is difference between
#define PUT(p, val) (*(unsigned long *)(p) = (val))
#define SET_NEXT_PTR(p, ptr) (*(char**)(p) = (char*)((unsigned long)(ptr)))
I'm experimenting with lldb and I wrote a simple C application. I want to debug it in terminal using lldb. When I want to see the stack frame, i get a memory read error:
(lldb) target create "./auth_overflow"
Current executable set to './auth_overflow' (x86_64).
(lldb) br s -l 25
Breakpoint 1: where = auth_overflow`main + 69 at auth_overflow.c:25, address = 0x0000000100000e25
(lldb) br s -l 9
Breakpoint 2: where = auth_overflow`check_authentication + 47 at auth_overflow.c:9, address = 0x0000000100000d5f
(lldb) br s -l 16
Breakpoint 3: where = auth_overflow`check_authentication + 138 at auth_overflow.c:16, address = 0x0000000100000dba
(lldb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Process 413 launched: './auth_overflow' (x86_64)
Process 413 stopped
* thread #1: tid = 0x33d2, 0x0000000100000e25 auth_overflow`main(argc=2, argv=0x00007fff5fbffcc0) + 69 at auth_overflow.c:25, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000e25 auth_overflow`main(argc=2, argv=0x00007fff5fbffcc0) + 69 at auth_overflow.c:25
22 exit(0);
23 }
24
-> 25 if(check_authentication(argv[1])) {
26 printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
27 printf(" Access Granted.\n");
28 printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
(lldb) re r esp
esp = 0x5fbffc70
(lldb) x/16xw $esp
error: memory read failed for 0x5fbffc00
(lldb)
What do you suggest , I should do?
EDIT : Actually I don't want to debug the application, just to see how it works on lower level. Because of this I'd like to see the content of the current stack frame, something like this:
(lldb) x/16xw $esp
0xbffff7e0: 0xb8000ce0 0x00000002 0x00000000 0xb7fd6ff4
0xbffff7f0: 0x40f5f7f0 0x00000000 0x00000002 0x08048474
0xbffff800: 0x08048510 0xbffff874 0x00000001 0x00000001
0xbffff810: 0xbffff848 0x00000000 0xb8000ff4 0x08048371
(lldb)
This:
Current executable set to './auth_overflow' (x86_64).
shows you're on a 64 bit machine. That being the case, you want the 64 bit rsp register, not the 32 bit esp register. esp will give you the least significant 32 bits of the contents of rsp, which in this case is obviously not yielding a valid address for you.
x/16xw $rsp
is what you're looking for.
Sample LLDB session:
paul#horus:~/Documents/src/sandbox$ lldb ./testldb
(lldb) target create "./testldb"
Current executable set to './testldb' (x86_64).
(lldb) list testldb.c
1 #include <stdio.h>
2
3 void func(int i) {
4 printf("In func() with value %d\n", i);
5 }
6
7 int main(void) {
8 func(3);
9 return 0;
10 }
11
(lldb) b testldb.c:4
Breakpoint 1: where = testldb`func + 18 at testldb.c:4, address = 0x0000000100000f22
(lldb) run
Process 48270 launched: './testldb' (x86_64)
Process 48270 stopped
* thread #1: tid = 0xb8dbca, 0x0000000100000f22 testldb`func(i=3) + 18 at testldb.c:4, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000f22 testldb`func(i=3) + 18 at testldb.c:4
1 #include <stdio.h>
2
3 void func(int i) {
-> 4 printf("In func() with value %d\n", i);
5 }
6
7 int main(void) {
(lldb) frame variable
(int) i = 3
(lldb) print &i
(int *) $0 = 0x00007fff5fbff9dc
(lldb) register read $rsp
rsp = 0x00007fff5fbff9d0
(lldb) x/16xw $rsp
0x7fff5fbff9d0: 0x00000000 0x00000000 0x00000000 0x00000003
0x7fff5fbff9e0: 0x5fbffa00 0x00007fff 0x00000f59 0x00000001
0x7fff5fbff9f0: 0x5fbffa18 0x00007fff 0x5fc0105e 0x00000000
0x7fff5fbffa00: 0x5fbffa18 0x00007fff 0x8fdc25fd 0x00007fff
(lldb)
I am new to GDB, so I have some questions:
How can I look at content of the stack?
Example: to see content of register, I type info registers. For the stack, what should it be?
How can I see the content of $0x4(%esp)? When I type print /d $0x4(%esp), GDB gives an error.
Platform: Linux and GDB
info frame to show the stack frame info
To read the memory at given addresses you should take a look at x
x/x $esp for hex x/d $esp for signed x/u $esp for unsigned etc. x uses the format syntax, you could also take a look at the current instruction via x/i $eip etc.
Use:
bt - backtrace: show stack functions and args
info frame - show stack start/end/args/locals pointers
x/100x $sp - show stack memory
(gdb) bt
#0 zzz () at zzz.c:96
#1 0xf7d39cba in yyy (arg=arg#entry=0x0) at yyy.c:542
#2 0xf7d3a4f6 in yyyinit () at yyy.c:590
#3 0x0804ac0c in gnninit () at gnn.c:374
#4 main (argc=1, argv=0xffffd5e4) at gnn.c:389
(gdb) info frame
Stack level 0, frame at 0xffeac770:
eip = 0x8049047 in main (goo.c:291); saved eip 0xf7f1fea1
source language c.
Arglist at 0xffeac768, args: argc=1, argv=0xffffd5e4
Locals at 0xffeac768, Previous frame's sp is 0xffeac770
Saved registers:
ebx at 0xffeac75c, ebp at 0xffeac768, esi at 0xffeac760, edi at 0xffeac764, eip at 0xffeac76c
(gdb) x/10x $sp
0xffeac63c: 0xf7d39cba 0xf7d3c0d8 0xf7d3c21b 0x00000001
0xffeac64c: 0xf78d133f 0xffeac6f4 0xf7a14450 0xffeac678
0xffeac65c: 0x00000000 0xf7d3790e
You need to use gdb's memory-display commands. The basic one is x, for examine. There's an example on the linked-to page that uses
gdb> x/4xw $sp
to print "four words (w ) of memory above the stack pointer (here, $sp) in hexadecimal (x)". The quotation is slightly paraphrased.
I want to find the address of a string in memory. In this case, I'm looking for "/bin/sh". Its an initialized variable, so its in the .data section and after compilation, it has a fixed address. So what do I do in GDB to find out its memory address? And I do not know the name of the variable its stored in.
Using info proc map sounds like a better approach to me.
(gdb) info proc map
process 930
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x400000 0x401000 0x1000 0x0 /myapp
0x600000 0x601000 0x1000 0x0 /myapp
0x601000 0x602000 0x1000 0x1000 /myapp
0x7ffff7a1c000 0x7ffff7bd2000 0x1b6000 0x0 /usr/lib64/libc-2.17.so
0x7ffff7bd2000 0x7ffff7dd2000 0x200000 0x1b6000 /usr/lib64/libc-2.17.so
0x7ffff7dd2000 0x7ffff7dd6000 0x4000 0x1b6000 /usr/lib64/libc-2.17.so
0x7ffff7dd6000 0x7ffff7dd8000 0x2000 0x1ba000 /usr/lib64/libc-2.17.so
(gdb) find 0x7ffff7a1c000,0x7ffff7bd2000,"/bin/sh"
0x7ffff7b98489
1 pattern found.
(gdb) x /s 0x7ffff7b98489
0x7ffff7b98489: "/bin/sh"
(gdb) x /xg 0x7ffff7b98489
0x7ffff7b98489: 0x0068732f6e69622f
If you want to search in the whole address space of the process, you need to get the memory mapping for your process and use the start address the end address with the find command in gdb.for instance, if cat /proc/$PID/maps shows that your process's virtual memory ranges from 0x08048000 to 0xc0000000 you can search as follows:
(gdb) find 0x80048000, 0xc0000000, "/bin/sh"
Another way to get the memory mapping of your process is using the gdb's embedded command :
(gdb) info proc map
Use the find command.
find [/sn] start_addr, +len, val1 [, val2, …]
find [/sn] start_addr, end_addr, val1 [, val2, …]
Search memory for the sequence of bytes specified by val1, val2, etc.
The search begins at address start_addr and continues for either len
bytes or through to end_addr inclusive.
s and n are optional parameters. They may be specified in either
order, apart or together.
s, search query size The size of each search query value.
b bytes
h halfwords (two bytes)
w words (four bytes)
g giant words (eight bytes)
All values are interpreted in the current language. This means, for
example, that if the current source language is C/C++ then searching
for the string “hello” includes the trailing ’\0’.
If the value size is not specified, it is taken from the value’s type
in the current language. This is useful when one wants to specify the
search pattern as a mixture of types. Note that this means, for
example, that in the case of C-like languages a search for an untyped
0x42 will search for ‘(int) 0x42’ which is typically four bytes.
n, maximum number of finds The maximum number of matches to print. The
default is to print all finds.
You can use strings as search values. Quote them with double-quotes
("). The string value is copied into the search pattern byte by byte,
regardless of the endianness of the target and the size specification.
The address of each match found is printed as well as a count of the
number of matches found.
The address of the last value found is stored in convenience variable
‘$_’. A count of the number of matches is stored in ‘$numfound’.
Take this example:
1.find the string "Can not open script" .
2.gdb>info proc map
process 8636
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x8048000 0x8898000 0x850000 0x0 /home/lela/ask/mLinux32
0x8898000 0x8902000 0x6a000 0x850000 /home/lela/ask/mLinux32
0x8902000 0x8d4c000 0x44a000 0x0 [heap]
0xf6800000 0xf6821000 0x21000 0x0
0xf6821000 0xf6900000 0xdf000 0x0
0xf6a00000 0xf6a21000 0x21000 0x0
0xf6a21000 0xf6b00000 0xdf000 0x0
0xf6b00000 0xf6b21000 0x21000 0x0
0xf6b21000 0xf6c00000 0xdf000 0x0
0xf6cbf000 0xf6cc0000 0x1000 0x0
0xf6cc0000 0xf6d00000 0x40000 0x0
0xf6d00000 0xf6d21000 0x21000 0x0
0xf6d21000 0xf6e00000 0xdf000 0x0
0xf6e06000 0xf6e07000 0x1000 0x0
0xf6e07000 0xf6e47000 0x40000 0x0
0xf6e47000 0xf6e48000 0x1000 0x0
0xf6e48000 0xf6e88000 0x40000 0x0
0xf6e88000 0xf6e89000 0x1000 0x0
0xf6e89000 0xf794f000 0xac6000 0x0
0xf794f000 0xf7a4f000 0x100000 0x0
0xf7a4f000 0xf7c15000 0x1c6000 0x0
0xf7c15000 0xf7c17000 0x2000 0x0 /usr/lib/i386-linux-gnu/libgcc_s.so.1
0xf7c17000 0xf7c2d000 0x16000 0x2000 /usr/lib/i386-linux-gnu/libgcc_s.so.1
0xf7c2d000 0xf7c32000 0x5000 0x18000 /usr/lib/i386-linux-gnu/libgcc_s.so.1
0xf7c32000 0xf7c33000 0x1000 0x1c000 /usr/lib/i386-linux-gnu/libgcc_s.so.1
like this result.
3.use find command with the start address and end address,and string with string type length ex:{char[19]},likes below.
gdb➤ find 0x8048000, 0x8902000, {char[19]}"Can not open script"
0x8611234
1 pattern found.
gdb➤ x/s 0x8611234
0x8611234: "Can not open script file \"%s\" to execute.\n"
4.finish.