radareorg / radare2

UNIX-like reverse engineering framework and command-line toolset
https://www.radare.org/
GNU Lesser General Public License v3.0
20.69k stars 3.01k forks source link

Address of stack buffer under r2 debugger different than under gdb given same env & args #7819

Closed ghost closed 7 years ago

ghost commented 7 years ago

I'm working through some labs on buffer overflow's. Basic stack smashinig to overwrite EIP, return back into buffer itself to execute shellcode.

To try and isolate the correct stack return address when not running in a debugging environment I've taken the ouput of 'printenv' in the same CWD as I'm working and used that as my envfile for rarun2. I've manually adjusted the _= env variable to be the full path to my executbale (see below for full env file)

Using radare2 for debugging, the stack address of the oveflowed buffer is different than the one shown in gdb when args and environment variables are the same (ASLR is disabled).

Test Case
RPISEC MBE lab3C

Compile Options

gcc -z execstack -fno-stack-protector -maccumulate-outgoing-args -mpreferred-stack-boundary=2 -o lab3C lab3C.c

r2 version

radare2 1.6.0-git 15141 @ linux-x86-32 git.1.5.0-193-gb5c0c01
commit: b5c0c01c6b3d03acd45214781e021229709bdc96 build: 2017-06-25__05:56:25

Environment

testing@mbe-sandbox:~/RPISEC_MBE/labs/lab03$ uname -a
Linux mbe-sandbox 4.4.0-77-generic #98-Ubuntu SMP Wed Apr 26 08:33:44 UTC 2017 i686 i686 i686 GNU/Linux
testing@mbe-sandbox:~/RPISEC_MBE/labs/lab03$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.2 LTS
Release:    16.04
Codename:   xenial

r2 Debugging Session

testing@mbe-sandbox:~/RPISEC_MBE/labs/lab03$ r2 -d /home/testing/RPISEC_MBE/labs/lab03/lab3C -e dbg.profile=./lab3C.rarun2
Process with PID 1260 started...
= attach 1260 1260
bin.baddr 0x08048000
Using 0x8048000
Assuming filepath /home/testing/RPISEC_MBE/labs/lab03/lab3C
asm.bits 32
[0xb7fdba20]> db main+0x95
[0xb7fdba20]> dc
Selecting and continuing: 1260
********* ADMIN LOGIN PROMPT *********
Enter Username: verifying username....

Enter Password: 
hit breakpoint at: 80485b3
[0x080485b3]> dr=
 eax 0xbffff5b0      ebx 0x00000000      ecx 0xffffffff      edx 0xb7fcd870
 esi 0xb7fcc000      edi 0xbffff5f0      esp 0xbffff5a4      ebp 0xbffff5f8
 eip 0x080485b3      eflags 1PZI        oeax 0xffffffff     
[0x080485b3]> 

With the breakpoint above, we break just before fgets() call to request password. eax contains address of our buffer. So 0xbffff5b0.

With gdb the address of the buffer is reported as 0xbffff5d0. This appears to be the correct address in my environment as it's the one that allows for succesful exploitation outside of a debugging environment (no nop sled prepend, address lands directly at shellcode).

I'm running it under gdb with 'gdb /home/testing/RPISEC_MBE/labs/lab03/lab3C' , using 'set env' and 'unset env' to manually make the environment match exactly the envfile used by rarun2, and then running with 'r < /home/testing/RPISEC_MBE/labs/lab03/lab3C/lab3C_input.txt'

Is this a bug?

Maybe I'm misunderstanding but I was under the impression that given the same env and args the stack address should be the same in both debuggers. Am I introducing variance somewhere due to how I'm launching r2 debugging, using rarun2, etc...?

Supporting Information

rarun2 file

#!/home/testing/bin/rarun2
program=/home/testing/RPISEC_MBE/labs/lab03/lab3C
stdin=/home/testing/RPISEC_MBE/labs/lab03/lab3C_input.txt
clearenv=true
envfile=/home/testing/RPISEC_MBE/labs/lab03/lab3C_envfile.txt

env file

XDG_SESSION_ID=25
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=172.16.179.1 47030 22
SSH_TTY=/dev/pts/0
USER=testing
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
MAIL=/var/mail/testing
PATH=/home/testing/bin:/home/testing/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
PWD=/home/testing/RPISEC_MBE/labs/lab03
LANG=en_US.UTF-8
SHLVL=1
HOME=/home/testing
LANGUAGE=en_US:
LOGNAME=testing
SSH_CONNECTION=172.16.179.1 47030 172.16.179.134 22
LESSOPEN=| /usr/bin/lesspipe %s
XDG_RUNTIME_DIR=/run/user/1000
LESSCLOSE=/usr/bin/lesspipe %s %s
_=/home/testing/RPISEC_MBE/labs/lab03/lab3C
OLDPWD=/
ghost commented 7 years ago

ignore comment, user input error. See above.

ghost commented 7 years ago

gdb Debugging Session (env manually adjusted with gdb's 'set env' to match rarun2 env file)

Same env & args as r2 debug session above but at breakpoint the address of stack buffer (in eax at break) is show as 0xbffff5d0.

(gdb) show env
XDG_SESSION_ID=25
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=172.16.179.1 47030 22
SSH_TTY=/dev/pts/0
USER=testing
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
MAIL=/var/mail/testing
PATH=/home/testing/bin:/home/testing/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
PWD=/home/testing/RPISEC_MBE/labs/lab03
LANG=en_US.UTF-8
SHLVL=1
HOME=/home/testing
LANGUAGE=en_US:
LOGNAME=testing
SSH_CONNECTION=172.16.179.1 47030 172.16.179.134 22
LESSOPEN=| /usr/bin/lesspipe %s
XDG_RUNTIME_DIR=/run/user/1000
LESSCLOSE=/usr/bin/lesspipe %s %s
_=/home/testing/RPISEC_MBE/labs/lab03/lab3C
OLDPWD=/
(gdb) disas main
Dump of assembler code for function main:
   0x0804851e <+0>: push   %ebp
   0x0804851f <+1>: mov    %esp,%ebp
   0x08048521 <+3>: push   %edi
   0x08048522 <+4>: sub    $0x50,%esp
   0x08048525 <+7>: lea    -0x48(%ebp),%edx
   0x08048528 <+10>:    mov    $0x0,%eax
   0x0804852d <+15>:    mov    $0x10,%ecx
   0x08048532 <+20>:    mov    %edx,%edi
   0x08048534 <+22>:    rep stos %eax,%es:(%edi)
   0x08048536 <+24>:    movl   $0x0,-0x8(%ebp)
   0x0804853d <+31>:    movl   $0x80486a8,(%esp)
   0x08048544 <+38>:    call   0x8048390 <puts@plt>
   0x08048549 <+43>:    movl   $0x80486cf,(%esp)
   0x08048550 <+50>:    call   0x8048370 <printf@plt>
   0x08048555 <+55>:    mov    0x804a040,%eax
   0x0804855a <+60>:    mov    %eax,0x8(%esp)
   0x0804855e <+64>:    movl   $0x100,0x4(%esp)
   0x08048566 <+72>:    movl   $0x804a060,(%esp)
   0x0804856d <+79>:    call   0x8048380 <fgets@plt>
   0x08048572 <+84>:    call   0x80484cb <verify_user_name>
   0x08048577 <+89>:    mov    %eax,-0x8(%ebp)
   0x0804857a <+92>:    cmpl   $0x0,-0x8(%ebp)
   0x0804857e <+96>:    je     0x8048593 <main+117>
   0x08048580 <+98>:    movl   $0x80486e0,(%esp)
   0x08048587 <+105>:   call   0x8048390 <puts@plt>
   0x0804858c <+110>:   mov    $0x1,%eax
   0x08048591 <+115>:   jmp    0x80485ed <main+207>
   0x08048593 <+117>:   movl   $0x80486fd,(%esp)
   0x0804859a <+124>:   call   0x8048390 <puts@plt>
   0x0804859f <+129>:   mov    0x804a040,%eax
   0x080485a4 <+134>:   mov    %eax,0x8(%esp)
   0x080485a8 <+138>:   movl   $0x64,0x4(%esp)
   0x080485b0 <+146>:   lea    -0x48(%ebp),%eax
   0x080485b3 <+149>:   mov    %eax,(%esp)
   0x080485b6 <+152>:   call   0x8048380 <fgets@plt>
   0x080485bb <+157>:   lea    -0x48(%ebp),%eax
   0x080485be <+160>:   mov    %eax,(%esp)
   0x080485c1 <+163>:   call   0x80484fb <verify_user_pass>
   0x080485c6 <+168>:   mov    %eax,-0x8(%ebp)
   0x080485c9 <+171>:   cmpl   $0x0,-0x8(%ebp)
   0x080485cd <+175>:   je     0x80485d5 <main+183>
   0x080485cf <+177>:   cmpl   $0x0,-0x8(%ebp)
   0x080485d3 <+181>:   je     0x80485e8 <main+202>
   0x080485d5 <+183>:   movl   $0x804870e,(%esp)
   0x080485dc <+190>:   call   0x8048390 <puts@plt>
   0x080485e1 <+195>:   mov    $0x1,%eax
   0x080485e6 <+200>:   jmp    0x80485ed <main+207>
   0x080485e8 <+202>:   mov    $0x0,%eax
   0x080485ed <+207>:   add    $0x50,%esp
   0x080485f0 <+210>:   pop    %edi
   0x080485f1 <+211>:   pop    %ebp
   0x080485f2 <+212>:   ret    
End of assembler dump.
(gdb) b *main+149
Breakpoint 1 at 0x80485b3
(gdb)  r < /home/testing/RPISEC_MBE/labs/lab03/lab3C_input.txt
Starting program: /home/testing/RPISEC_MBE/labs/lab03/lab3C < /home/testing/RPISEC_MBE/labs/lab03/lab3C_input.txt
********* ADMIN LOGIN PROMPT *********
Enter Username: verifying username....

Enter Password: 

Breakpoint 1, 0x080485b3 in main ()
(gdb) info registers
eax            0xbffff5d0   -1073744432
ecx            0xffffffff   -1
edx            0xb7fcd870   -1208166288
ebx            0x0  0
esp            0xbffff5c4   0xbffff5c4
ebp            0xbffff618   0xbffff618
esi            0xb7fcc000   -1208172544
edi            0xbffff610   -1073744368
eip            0x80485b3    0x80485b3 <main+149>
eflags         0x246    [ PF ZF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51
ghost commented 7 years ago

Or looking at this another way, if you simply clear all environment variables under both r2 and gdb, the buffer (and stack) addresses are also not consistent between r2 & gdb,

r2 with clearenv=true in rarun2 profile

hit breakpoint at: 80485b3
[0x080485b3]> dr=
 eax 0xbffffdf0      ebx 0x00000000      ecx 0xffffffff      edx 0xb7fcd870
 esi 0xb7fcc000      edi 0xbffffe30      esp 0xbffffde4      ebp 0xbffffe38
 eip 0x080485b3      eflags 1PZI        oeax 0xffffffff     
[0x080485b3]> 

gdb with all env variables deleted using 'unset env'

eax            0xbffffdc0   -1073742400
ecx            0xffffffff   -1
edx            0xb7fcd870   -1208166288
ebx            0x0  0
esp            0xbffffdb4   0xbffffdb4
ebp            0xbffffe08   0xbffffe08
esi            0xb7fcc000   -1208172544
edi            0xbffffe00   -1073742336
eip            0x80485b3    0x80485b3 <main+149>
eflags         0x246    [ PF ZF IF ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x33 51

Again, not sure if this is legitimately a bug, or if this is normal & just part of different debugger implementation, etc...

ghost commented 7 years ago

I think I may have found the issue described in my first comment: r2 w/ rarun2 envfile vs. gdb with manually adjusted env vars.

Normally environment variable strings on the stack are separated by a \x00 byte. You can observe this by debugging any program in r2 and examining the strings pointed to by the pointers in envp.

Env variable strings under 'untouched' environment. Strings delimited by \x00

0xbffff7d0  0000 0000 2f68 6f6d 652f 7465 7374  ..../home/test                                      
0xbffff7de  696e 672f 5250 4953 4543 5f4d 4245  ing/RPISEC_MBE                                      
0xbffff7ec  2f6c 6162 732f 6c61 6230 332f 6c61  /labs/lab03/la                                      
0xbffff7fa  6233 4300 5844 475f 5345 5353 494f  b3C.XDG_SESSIO                                      
0xbffff808  4e5f 4944 3d32 3500 5445 524d 3d78  N_ID=25.TERM=x                                      
0xbffff816  7465 726d 0053 4845 4c4c 3d2f 6269  term.SHELL=/bi                                      
0xbffff824  6e2f 6261 7368 0053 5348 5f43 4c49  n/bash.SSH_CLI                                      
0xbffff832  454e 543d 3137 322e 3136 2e31 3739  ENT=172.16.179                                      
0xbffff840  2e31 2034 3730 3330 2032 3200 5353  .1 47030 22.SS                                      
0xbffff84e  485f 5454 593d 2f64 6576 2f70 7473  H_TTY=/dev/pts                                      
0xbffff85c  2f30 0055 5345 523d 7465 7374 696e  /0.USER=testin                                      
0xbffff86a  6700 4c53 5f43 4f4c 4f52 533d 7273  g.LS_COLORS=rs                                      
0xbffff878  3d30 3a64 693d 3031 3b33 343a 6c6e  =0:di=01;34:ln

However when using rarun2's envfile= directive to pass a file of environment variables to radare2, the env variable strings end up separated by \x0a\x00 bytes on the stack. So for each env variable added you're adding one more byte to the stack than you would have under a normal execution given the same environment.

**Env Variable strings using rarun2 envfile=. Strings delimited by \x0a\x00. Stack address has been offset to lower address by extra bytes.***

0xbffff7b0  0000 0000 0000 0000 0000 0000 0000 2f68  ............../h                               
0xbffff7c0  6f6d 652f 7465 7374 696e 672f 5250 4953  ome/testing/RPIS                               
0xbffff7d0  4543 5f4d 4245 2f6c 6162 732f 6c61 6230  EC_MBE/labs/lab0                               
0xbffff7e0  332f 6c61 6233 4300 5844 475f 5345 5353  3/lab3C.XDG_SESS                               
0xbffff7f0  494f 4e5f 4944 3d32 350a 0054 4552 4d3d  ION_ID=25..TERM=                               
0xbffff800  7874 6572 6d0a 0053 4845 4c4c 3d2f 6269  xterm..SHELL=/bi                               
0xbffff810  6e2f 6261 7368 0a00 5353 485f 434c 4945  n/bash..SSH_CLIE                               
0xbffff820  4e54 3d31 3732 2e31 362e 3137 392e 3120  NT=172.16.179.1                                
0xbffff830  3437 3033 3020 3232 0a00 5353 485f 5454  47030 22..SSH_TT                               
0xbffff840  593d 2f64 6576 2f70 7473 2f30 0a00 5553  Y=/dev/pts/0..US                               
0xbffff850  4552 3d74 6573 7469 6e67 0a00 4c53 5f43  ER=testing..LS_C                               
0xbffff860  4f4c 4f52 533d 7273 3d30 3a64 693d 3031  OLORS=rs=0:di=01 

To test further, instead of using envfile= in my rarun2 profile to set my env vars, I added a series of setenv= lines in my rarun2 profile for each of the environment variables in the envfile I was using.

Done that way, debugging the same program with the same env variables under r2 and gdb results in exactly the same stack addresses.

Regarding my other comment: r2 with clearenv=true vs. gdb with 'unset env', gdb doesn't actually fully clear all variables when you do 'unset env' it seems. I still had SHLVL= and PWD= present in stack memory when debugging under gdb despite gdb showing nothing when I ran 'show env'. r2 with clearenv=true does clear all the env variables. So this explains stack address variance in that scenario.

jpenalbae commented 7 years ago

Fixed on 42836cb353d530289d4f9ff6f19843a93173b3a8. Rebuild from latest git version and close the issue if the patch does the job for you.

ghost commented 7 years ago

Seems fixed to me.

Environment variables added via rarun2's envfile option are now seperated by only \x00 and not \x0a\x00.

Given no ASLR, same environment & same args gdb and r2 now show the same stack addresses.

Closing as fixed.