周末祥云杯没打,主要是自己想摸了。。(就是这么直白)还有就是nctf举办,我出题,我到比赛那天还没出完。。。(太咕了。。)
比赛后就想来复现这比赛,看解题人数,感觉满难的,应该很有质量,就跟着null的wp复现吧,一天复现一题
re1
动态调试,发现对flag的每一位进行相同的操作,慢慢看太多了,因此可以gdb脚本爆破,
null的脚本写错了把。。程序开了pie,第一句就不对。。。而且while也没让程序重新启动,这里给出我写的
pwndbg> define f1
Type commands for definition of "f1".
End with a line saying just "end".
>b *$rebase(0x6ce)
>b *$rebase(0x18096)
>set $result = 0x20
>python f = open("log","w+")
>while($result < 0x80)
>r < test //自己的文件flag{12345678901234567890123456789012}
>set *(char *)$rdi=$result
>python f.write(gdb.execute("p $result",to_string = True))
>c
>python s = gdb.execute("x/bx $rdi",to_string = True)
>python f.write(s)
>python f.flush()
>set $result = $result + 1
>end
>end
之后逐位对照就行,
尝试用angr写了脚本,发现运行不起来,如果有师傅会写,希望能告诉我,tcl…
看评论可以用插桩,学习了一下pin
写的脚本(基本是模板,改一些就行)
#!/usr/bin/env python
# coding=utf-8
import subprocess
import os
import logging
import json
import string
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# js = json.dumps(ssst, sort_keys=True, indent=4, separators=(',', ':'))# format json output
class shell(object):
def runCmd(self, cmd):
res = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
sout, serr = res.communicate()
return res.returncode, sout, serr, res.pid
def initPin(self, cmd):
res = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
self.res = res
def pinWrite(self, input):
self.res.stdin.write(input)
def pinRun(self):
sout, serr = self.res.communicate()
return sout, serr
filename = "./main"
cmd = "/root/tool/ctf/pin/pintool/pin -t " + \
"/root/tool/ctf/pin/pintool/source/tools/ManualExamples/obj-intel64/inscount0.so" + " -- " + filename
# print shell.runCmd(cmd)
cout_old = 0
# for i in range(30):
# res = subprocess.Popen(cmd,shell=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
# res.stdin.write("a"*i+'\n')
# sout,serr = res.communicate()
# cout = sout.split("Count ")[1]
# cout_sub= int(cout) - cout_old
# cout_old = int(cout)
# print ("current len ", i,"current count:",cout,"sub_count ",cout_sub)
shell = shell()
#shell.initPin(cmd)
cout_old=0
cur=''
j = 0
cout_sub = 0
dic = string.digits+"b"+string.letters+'_{}'+string.digits
for i in range(33):
for j in range(len(dic)):
if cout_sub < 0 and cout_sub>-3:
cout_old = cout_old - cout_sub
shell.initPin(cmd)
pwd = "flag{"+cur+dic[j]+'?'*(31-len(cur)) + "}"
print pwd
shell.pinWrite(pwd)
sout,serr = shell.pinRun()
cout = sout.split("Count ")[1]
cout_sub= int(cout) - cout_old
cout_old = int(cout)
if cout_sub > 0 and cout_sub < 3:
cur=cur+dic[j]
break
print ("current cur ", cur,"current count:",cout,"sub_count ",cout_sub)
打工人
服了 ,终于逆出来了,这个由go写的lua虚拟机真尼玛的难逆,加密满简单的,就是des-cbc,后再base58,但关键是真tm的难看出来啊。。。
说一下过程,别问我怎么来的,全是动手调出来的。。。0000000005718B0是main.main函数,go语言写的,很容易看出来,再根据经验,main.main往往在函数列表最后,再慢慢调可以得到。。
00000000004F4B50是lua语言的解释器
作者github上找的,没删网址,应该是他的一点友善了吧。。
https://github.com/yuin/gopher-lua
https://github.com/tengattack/gluacrypto/
他所应用的
在main函数调用lua的解释器之前,查看它的参数,可以看到lua的脚本
b 'function joke()',0Ah
debug030:000000C0000EC000 db ' return "3".. "2".. "7".. "a".. "6".. "c".. "4".. "3".. "0".. '
debug030:000000C0000EC000 db '"4".. "a".. "d".. "5".. "9".. "3".. "8".. "e".. "a".. "f".. "0"..'
debug030:000000C0000EC000 db ' "e".. "f".. "b".. "6".. "c".. "c".. "3".. "e".. "5".. "3".. "d".'
debug030:000000C0000EC000 db '. "c"',0Ah
debug030:000000C0000EC000 db 'end',0Ah
debug030:000000C0000EC000 db 's = joke()',0Ah
debug030:000000C0000EC000 db 'local m = require("crypto")',0Ah
debug030:000000C0000EC000 db 'f="fake"',0Ah
debug030:000000C0000EC000 db 'if(m.md5(',27h,'flag',27h,') == s)',0Ah
debug030:000000C0000EC000 db 'then',0Ah
debug030:000000C0000EC000 db 9,'a=io.read("*l")',0Ah
debug030:000000C0000EC000 db 9,'r = m.encrypt(a, "enjoy" ,',27h,'flagflag',27h,', 0, "a = f+ a"'
debug030:000000C0000EC000 db ')',0Ah
debug030:000000C0000EC000 db 'else',0Ah
debug030:000000C0000EC000 db 9,'print("wrong")',0Ah
debug030:000000C0000EC000 db 9,'error({error="input wrong"})',0Ah
debug030:000000C0000EC000 db 'end',0Ah
debug030:000000C0000EC000 db 0Ah,0
首先应该输入“flag”与MD5一样,之后再输入进行加密,至于des-cbc是怎么看出来的,调的,再结合给出github网址,作者好恶心,还魔改des-cbc改成enjoy,iv改成了“flagflag”^"a = f+ a"后的字符串,注意这里的“a = f+ a”是字符长,不是式子,当时调的时候,怎么也找不到f+a后的字符长,只找到了“a = f+ a”,太误导人了。。。。。
0000000000571410 base58 看表,发现
之后就是比较
解密脚本
from Crypto.Cipher import DES
from base58 import *
from binascii import a2b_hex
cip = b58decode("YjNiZejTKW37A3FtSwV3xSMYRjDpMnsUBCJqK7DZ5mAnfQvGd8KjgpG4yYA2v5BmY67iemDJvH8x8a5NLaSmbvKyemMGsx2SaQoc7kpy1gKQU")
cip = '1f8c11a43c1e321cd7a1dc3b1cc6665f0bd83d2d6058be3f684162e2c91c33f67c21eb3faf1a1f42'
#reversed(cip)
cip = a2b_hex(cip)
iv = "\x07\x4c\x5c\x47\x00\x47\x41\x06"#"flagflag"xor "a = f+ a"后的
key = "flagflag"
#cip = "4567\x04\x04\x04\x04"
des = DES.new(key,DES.MODE_CBC,iv)
flag = des.decrypt(cip)
print(flag)
总的来说,下次碰到这种,应该秒做了,这一次逆的想死了