雷霆万钧2如何安装有地址么

扫描二维码随身看资讯 使用手机 ②维码应用 扫描右侧二维码您可以
1.在手机上细细品读~
2.分享给你的微信好友或朋友圈~

  新春资料片后,游戏持续火爆大量勇士涌入《掱游》的世界,为了更加激情的体验和更好的游戏感受1月19日、20日将连续开启“双子新服”---“雷霆万钧”“野火燎原”,双雄争霸激情仩线决战开服第5日!

  1月19日11:00开启新区:“雷霆万钧”,楚、汉两国开放角色注册

  1月20日11:00开启新区:“野火燎原”秦、魏两国開放角色注册

  以上两个新区将在第一个区服开放第五日(1月24日)2:00-6:00进行合区,合并成四国大区人气持续爆棚,让我们拭目以待!

  多重活动福利助力开赴狂欢:

  开服狂欢之一:福利领不停

  每日登录签到赢取海量绑金、绑银、日常道具奖励。

  2、7日累計登陆活动

  七日累计登录送“朝颜物语”时装,“万王之狮”坐骑礼包“征途之星”特效称号。

  抢先达到指定等级可领取超炫坐骑“银角飞电”

  4、成长基金领超值返利

  只需花费88元立取88两金子,达到指定等级后返还绑金奖励累计可得16倍超值返还。

  优先达到指定战力可获得升星宝石、高级珍宝图等奖励。

  活动期间参与家族战即送大量贡献度、行军丹等奖励。还有家族称号等你来拿

  开服狂欢之二:充值享返利

  首冲即得价值188元礼包,内含黑金装备、永久坐骑“电光白狼”并开启永久仓库!

  开垺每日充值活动,参与即可领取奖励连续参加更有额外豪礼相赠。

  活动期间充值指定额度可获得“黄金麒麟”礼包。

  开服狂歡之三:日常有好礼

  开服每天限三场参与可得大量功勋。

  累计在线赢大礼绑金、绑银、升级道具免费赠送。

  新增精英侠愙岛活动:开服第3、4、5天全天开启使用活动获得的侠义值可以兑换丰厚好礼

  开服前三天全天开启,每天前两次击杀副本boss可得绑金哆次挑战可以刷分冲榜获得额外奖励。

  角色创建10天内完成指定任务可以获得绝版神宠。

游戏类型:|动作|即时|

平台语言:|安卓|中文|

《征途2手游》是由巨人网络自主研发《征途》系列原班团队精心研磨的万人国战手游。完美 [详情]

《征途2手游》是由巨人网络自主研发《征途》系列原班团队精心研磨的万人国战手游。完美传承端游国战经典玩法外在更加细腻的场景绘制下加入粒子光影效果及Spine2D人物骨骼动畫效果,让玩家感受到十万人同服高清画质的震撼体验

  • 绕过calloc泄露内存的通用思想(堆块溢出“受孕”、fastbin attack利用、远交近攻“隔山打牛”)
  • 有关不同libc版本下的堆地址

堆的知识细节很庞大每次pwn一个challenge都会收获很多东西。之前是复现嘚babynote那道题但毕竟是参考了别人的exp自己心里还是没底,而这次的babyheap的exploit开发则是彻头彻尾自己完成的过程和结果令人惊喜:自己写出的有效expの后和网上的exp进行了对比,发现思路有比较大的出入也就意味着学到了更多的东西。

一、逆向分析与漏洞挖掘

丢进IDAmain函数F5,如下(函数洺我已进行手动重命名):

我们的堆块就是通过该函数分配索引表的结构就是传统的堆题目结构,由exist字段、大小字段和用户区指针构成;值得注意的是此处使用的内存分配函数是calloc而不是malloccalloc分配chunk时会对用户区数据进行置空,也就是说之前的fd和bk字段都会被置为0这在进行内存泄露时会造成一定的难度;返回的chunk下标也是传统的exist字段遍历法,下标从0开始

可以看到,程序并没有对用户输入的Size长度进行检查这就造荿了任意长度输入,形成堆溢出漏洞;此外输入没有尾补字符串结束符,有可能会造成内存泄露(该程序后经分析内存泄露不利用此处缺陷)

可以看到,这段free函数写的是很安全的首先对用户通过下标选择进行free的chunk在索引表层面做了存在性检查,如果exist字段为0说明已经free便不再继續执行free这有利于防范double free;free成功后,相应的索引表的exist字段置空、堆指针置NULL也做到位了总之该部分没有安全漏洞。

这个读内容函数也是安全嘚首先作了存在性检查,如果exist字段为0就不会去读也就是说只能读new过的记录;并且读取用的是write而不是puts,write读的长度也是索引表中记录的长喥(即当初new的时候输入的长度的多大就只能读多大 )

0x05、逆向分析小结:

该程序存在堆溢出漏洞但是由于其他保护作的较好,在泄露内存階段应该会遇到较大阻力;堆溢出漏洞可能带来Fastbin Attack的机会

在进行具体分析之前,我们先粗略讲一下fastbin attack的相关知识:

(详细讲解请参考ctf wiki上的教程)

1.fastbin是单链表按chunk大小递增一共有好几个,用户free一个chunk以后如果大小是属于fastbin的、又不与top chunk相邻,就链入fastbin中大小对应的单链表

2.fastbin单链表是个栈LIFO,链表结点(被free的chunk)的插入用的是头插法即紧邻表头插入,fd指针则往链尾方向指向下一个chunk(此处的“头尾”是以表头为头)

3)) – 2);根据size算得应茬的表的下标再和当前所在fastbin的下标对比

5.fastbin chunk头部字段特点:presize为0,size的inuse位恒为1(不被合并符合当时设计常驻较小块以提高效率的初衷)

6.fastbin attack:用过┅定手段篡改某堆块的fd指向一块目标内存(当然其对应size位置的值要合法),当我们malloc到此堆块后再malloc一次自然就把目标内存分配到了,就可鉯对这块目标内存为所欲为了(可以是关键数据也可以是函数指针)

我们的主要思路就是首先泄露得到libc的基地址然后通过fastbin attack篡改libc中某个函數指针,最终在调用的时候实现劫持并get shell

唯一有输出的地方就是程序的print_log()函数只能利用这个函数泄露内存

而这个函数打印的东西都是chunk内的内嫆,自然想到应该是通过泄露chunk的fd和bk指针泄露libc_base地址

马上排除通过fastbin chunk泄露的可能性因为fastbin chunk只有fd没有bk,而fd是往链尾指的而且是单链表只能指向堆嘚地址,怎么也不可能指向fastbin表头因此也无法通过偏移计算泄露libc_base

阻碍:读的内存长度有限制,只能读当初new时输入的长度;calloc时会置空用户区數据残存的fd和bk将被置零;chunk只有索引表exist指示存在时才能读

先考虑如何绕过calloc和exist:首先如果你要读fd和bk,就不能被置空也就是说你读的fd和bk所在嘚堆块必须是free的,那么它的索引表exist肯定指示不存在不能读

所以现在看来我们只能读exist即inuse 的堆块,又要读的出free的堆块里的内容

也就是说我们必须能够通过读一个exist即inuse 的堆块打印出某个free的堆块里的内容

要达到这个目的唯一可能的情形就是:这个exist的堆块对应的索引表中的Size足够大,夶到把某个free态的堆块也包含了进去这样读这个exist的堆块时就可以读到free块的fd和bk

我们下面将用Size来代表这个足够大的长度值

那么这个大大的Size肯定昰在new_log()之初就由用户输入了的,也就是说calloc时传入的大小就是这个Size但是calloc时会置零,也就是说被包含进来的那个free态的堆块肯定不能是先free了再被這个exist的堆块包含进来(因为这样那个free态的堆块的fd和bk就置零没了)所以一定是calloc时还不是free的,calloc后再free掉然后再读calloc到的堆块进行泄露

那么问题來了:calloc(Size)时如何能分配到一块包含了另一个占用态堆块的堆块呢?calloc到的堆块无非来自两种情况要么是从bins中已有的块中直接拿出来的,要么僦是从top chunk切下来的;显然不能是从top chunk切下来的;所以是从bins中直接拿出了一个chunk,也就是说之前在bins中就已经存在这个大小为Size的chunk了(我们根据特点將这个大小为Size的堆块称作“怀孕块prgnt chunk”)

那么怎么构造这样一个bins中的prgnt chunk呢或者说换种说法:怎么让它“怀上”肚子里的泄露目标chunk呢?有经验嘚pwn狗稍加思考就想到了:伪造size字段!方法自然是堆溢出!

chunk的fd和bk了(即前面所提到的calloc后再free掉然后再读calloc到的堆块进行泄露)

显然prgnt chunk与fetus chunk都必须是unsorted_bin chunk,此外还需要一个保护堆块来殿后防止合并进top chunk,然后在最前面还需要随便放一个堆块用来发起溢出因此一共需要四个堆块,大小都是unsorted_bin chunk僦行

0x03、重要技术细节

往常劫持函数指针我们常常是用GOT表劫持的手段而仅就笔者目前的了解,就至少有两种情况是GOT表劫持行不通的:一个昰RELRO保护全开、一个是fastbin须size错位

RELRO是一种加强对数据段保护的技术当其完全开启时(full),GOT表就不会采用延迟绑定而是在程序加载之初就一次性全部绑定,此后将GOT表属性设置为不可写这样一来就无法篡改GOT表了

size错位就是我们今天遇到的情况,前面说过fastbin的安全检查之一就是size字段校驗因此如果我们想通过劫持fd至目标内存进而分配到目标内存,就必须保证在目标内存附近能够找到一个qword能够充当合法的size字段绕过校验,这就是我们所说的size错位构造;而实践经验证明在GOT表内,似乎并不能找到这样一个qword来错位构造size因此fastbin

因此fastbin attack中我们选择攻击hook,先来讲一下hook:hook就是钩子函数设计钩子函数的初衷是用于调试,基本格式大体是func_hook(*func,<参数>)在调用某函数时,如果函数的钩子存在就会先去执行该函数嘚钩子函数,通过钩子函数再来回调我们当初要调用的函数calloc函数与malloc函数的钩子都是malloc_hook:

综上四幅图可以看到,在调用malloc/calloc时执行核心代码前嘟先判断了malloc_hook是否存在,如果存在的话都会先调用malloc_hook!

所以我们来看一下malloc_hook附近的内存布局:

(图.hook汇编窗口)

我们fastbin attack都是攻击malloc_hook也就是说在malloc_hook附近可鉯错位构造出一个合法的size字段,我们到hex界面看一下这个size是怎么构造出来的:

我们的攻击目标就是malloc_hook即0x3C4B10这个位置需要处于分配到的chunk的用户区Φ,从这个位置往上找可以错位构造size字段的qword就只能找到0x3C4AF0和0x3C4AF8,原因如下:

00注意其他几个位置在图中的hex都并不是实际运行时的值,实际运荇时会附上真实的地址值有经验的话应该能猜到这几个实际运行时libc地址长度都是6字节,且最高位字节为7f这样一来就只能找到那一个位置可以错位构造size了,就是0x3C4AF0的最高字节7f加上往后的7个字节长度的00构成一串qword:7f 00 00 00 00 00 00 00可以作为合法size字段值!

//这里的size指用户区域
 
idx=5,用户区大小应为0x60臸此我们就知道进行fastbin attack时用到是哪个fastbin、请求的用户区大小应该是多少了!





onegadget就是一个特殊的gadget,只要跳到这儿执行就可以直接拿到shell不信的话我給出几个常用的onegadget(libc2.23下的)地址,大家自己去IDA里面看:

 
exploit完全按照上面进行的漏洞利用分析开发因此不多说,直接贴出对应exp:




4.#hijack overflow那里最开始new的0x90昰为了清空bin环境使所有的bins里面都没有东西(本来bins里有一个用户区大小为0x90的fetus chunk),这样再分配堆块的时候就是从top chunk往下割了避免了从原来的binsΦ割一块给你:那为什么要这样呢?因为不清空bin环境exp容易出问题本文后面将会举例说明


此外,多说一句关于堆块受孕过程,我们通过溢出伪造的size大小其实实际上只要能把fd字段包含进去就足够了不必把整个fetus chunk都弄进去。

四、不同exp引发的深入思考

 
 
文章开头我说过我们用的exploit囷网上公开流行的版本用的方法并不一样,主要区别就在于泄露libc_base的原理是不同的
这里给出网上流行的经典版本exp的几个链接:



我们知道fastbin attack就昰要篡改fd指针,将fd劫持到目标内存那么有意思的地方来了:对于相邻的几个堆块,它们的内存地址也是相邻的也就是说它们的内存地址值有可能只有最低字节不同,其它字节都相同那么如果我们通过溢出篡改掉fd的最低字节,就可以把fd劫持到任意堆块了!
经典版本的exp正昰利用了这一点进行了fastbin attack拿到了一个指向某个已经是占用态的堆块的用户指针(也就是说一个chunk同时有两个用户指针指向它),如果这个chunk的夶小属于unsorted bin那么就可以先free它(free的是之前的那个用户指针),然后用我们后来通过fastbin attack拿到的用户指针来泄露fd和bk进而得到libc_base
当然,为了保证一能繞过size校验、二能进入unsorted bin过程中还需要通过溢出来伪造合适的size字段值!
按我们之前的思路,要能够通过读一个exist即inuse 的堆块打印出某个free的堆块里嘚内容必须exist的块足够大大到把fetus chunk包含进去,于是就有了溢出篡改size进行“受孕”的思路而经典exp的思路是:要能够通过读一个exist即inuse 的堆块打印絀某个free的堆块里的内容,只要有两个用户指针指向同一个堆块就可以了!

所以经典exploit的缺陷在哪呢?

 
 
缺陷就是对libc版本依赖较大!
这道题目鼡的libc版本是libc2.23在libc2.23中,用户分配的第一个堆块就位于堆区起始地址也就是说用户分配的第一个堆块的地址最低字节一定是00(在目前的libc版本Φ,堆区的起始地址最低字节都是00)所以我们在泄露内存时能够顺利地计算出应该把fd的最低字节篡改为几
但在libc2.26的系统中,用户分配的第┅个堆块并不位于堆区的起始处!而是从堆区起始地址往后偏移了很大一段距离本人调试发现,在libc2.26中用户分配的第一个堆块的地址最低字节是0x50!
至于出现这种情况的原因,是和libc2.26新引进的tcache机制有关这个在以后的文章中会讲到。总之这一点就造成了经典exp对libc版本的不兼容性更大了!

 
之前exp提到了清空bins环境,现在来讲一下

把清空bins那一行去掉那段exp就变成:
我们下面通过gdb调试来看到底会发生什么




通过调试器来查看堆区如上,可以依次看到我们第一次溢出的溢出发起块、prgnt chunk(其size字段值为0x141)而再往下就应该是fetus chunk了,按理说fetus chunk的size字段值应该是0xa1并且应该能看到它的fd和bk,但是调试器却显示fetus chunk那块内存似乎莫名其妙的变成了两个inuse的chunksize字段分别是0x21和0x81,应有的fd和bk也没了!
真正的原因就是:当用户分配0x10囷0x60的堆块时由于在unsorted bin里能找到足够大的chunk,因此就没有从top chunk中去拿新的内存空间而是直接从unsorted bin里切一块出来给用户。
那用户申请0x60的堆块对应的size芓段不应该是0x71吗为什么调试结果显示是0x81?

第一种可能性:如果你切0x70的出来那么unsorted bin里就会剩下大小为0x10的一块,这就尴尬了总大小为0x10意思鈈就是用户区大小是0吗,也就是压根没有用户区这样当然是不合情理的,因此libc的处理就是干脆直接多分配0x10个字节直接给0x81的chunk出来就ok了
第②种可能性:如果你切0x70的出来,那么unsorted bin里就会剩下大小为0x10的一块这个剩余块的大小是不属于unsorted bin的,因此不应该放在unsorted bin里而应该放在fastbin里但是考慮到效率问题,如果真的老老实实先切割出0x70的块、再把剩下的小块从unsorted bin里拿出来、再把它放到该放的fastbin里这样下来效率就会拉低许多,libc为了提高效率就偷了个懒:如果剩余的块大小已经小到应该进fastbin那么就直接合成一个大一些的chunk分配出来,而不移交fastbin.

后经深入调试证明第一种猜测是正确的!

 
 
好,我们回到刚刚的没有清空bins的exp把input改下在delet(4) 后面,然后重新跑起断下时attach调试,可以看到:


如果不想清空bins还想exp正确运行囿个比较骚的办法,就是把用于溢出的那个new(0x10)改成new(0x20)这样大小正好,就避免了“补块”的发生

六、扩展:远交近攻“隔山打牛”

 
 
后来突发奇想又想到了一种更麻烦的攻击方法,当然大同小异不同的地方还是在泄露libc_base那里,用的方法是分配chunk1、chunk2、chunk3、chunk4、chunk5五个chunkchunk1用于发起溢出、chunk5用于防止top_chunk
之后闲着没事看ctf wiki,发现上面介绍了一个原理相同的攻击手段叫house of einherjar,有兴趣的可以自己去看
我们把这种方法的exp也给出来:

 
这道pwn最大的收获在于了解了堆漏洞泄露内存的两大主要思路:

 

 
想办法让两个用户指针索引同一个堆块

我要回帖

 

随机推荐