來自戰隊:@驢肉火燒
簽到
題目給出一張圖片,提示觀色,預計可能是將信息隱藏在某一色道中或 LSB 隱寫
將給出的圖片導入 StegSolve.jar,在 red plane 1 中發現半個 flag
利用 Frame Browser 對圖片進一步分析可以分離出第二張圖片,
同樣在 red plane 1 中發現另外半個 flag
熟悉的解密
附件壓縮包里面是一個文本文件,很明顯是數行用 base64 編碼的字符串
寫如下腳本進行解碼:
import base64
f1 = open('1.txt', 'r')
f2 = open('2.py', 'w')
line = f1.readline()
while line:
str = base64.b64decode(line).decode('utf-8')
f2.write(str)
line = f1.readline()
f1.close()
f2.close()
得到:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
from ctypes import *
def encipher(v, k):
y = c_uint32(v[0])
z = c_uint32(v[1])
sum = c_uint32(0)
delta = 0x9e3779b9
n = 32
w = [0,0]
while(n>0):
sum.value += delta
y.value += ( z.value << 4 ) + k[0] ^ z.value + sum.value ^ ( z.value >> 5 ) + k[1]
z.value += ( y.value << 4 ) + k[2] ^ y.value + sum.value ^ ( y.value >> 5 ) + k[3]
n -= 1
w[0] = y.value
w[1] = z.value
return w
def encodestr(text, key):
cipherList = []
text += (8 - len(text) % 8) * chr(0)
for i in range(len(text)/8):
v1 = 0
v2 = 0
for j in range(4):
v1+= ord(text[i*8+j]) << (4-j-1)*8
v2+= ord(text[i*8+j+4]) << (4-j-1)*8
cipherList.append(encipher([v1,v2],key))
return cipherList
if __name__ == "__main__":
key = [11,22,33,44]
flag = ?
cipher = encodestr(flag1,key)
#cipher = [[4018289233L, 2950320151L], [1771827478L, 493980876L], [1863284879L, 1137797599L], [2759701525L, 3957885055L], [2600866805L, 78850724L]]
程序的邏輯是將 flag 進行 encipher() 和 encodestr() 雙重加密得到五組由兩個整數組成的列表
由內向外來看,encipher() 里面有一個常數 0x9e3779b9,是利用 TEA 算法進行分組加密,由於 key 恆定,所以可以寫出逆算法解密
void decrypt (uint32_t* v, uint32_t* k) {
uint32_t v0=v[0], v1=v[1], sum=0xC6EF3720, i;
uint32_t delta=0x9e3779b9;
uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];
for (i=0; i<32; i++) {
v1 -= ((v0<<4) + k2) ^ (v0 + sum) ^ ((v0>>5) + k3);
v0 -= ((v1<<4) + k0) ^ (v1 + sum) ^ ((v1>>5) + k1);
sum -= delta;
}
v[0]=v0; v[1]=v1;
}
得到五組數據:
1718378855 2067085111
859137328 1663907428
808594737 828727597
942683954 758133808
1694498816 0
encodestr() 的核心大意是把一個字符串拆成八段,v1 和 v2 分別對每小段的前后部分的 ASCALL 位移后進行累加,最后拿去 encipher() 加密
此時我們已經知道 encipher() 加密前的數據,考慮逆向還原到字符
一個字符正好占用 1kb(8b),所以位移操作(位移數為 8 的倍數)仍舊使得每一位字符的摘要獨立,每四位拆開再從頭至尾拼接即可
exp 如下:
#include <bits/stdc++.h>
using namespace std;
int List[5][2]= {{1718378855,2067085111},
{859137328,1663907428},{808594737,828727597},
{942683954,758133808},{1694498816,0}};
int main() {
for (int i=0;i<5;i++) {
int now=List[i][0];
for (int j=0;j<4;j++) {
printf("%c",now>>(8*(3-j)));
now-=(now>>(8*(3-j)))<<(8*(3-j));
}
now=List[i][1];
for (int j=0;j<4;j++) {
printf("%c",now>>(8*(3-j)));
now-=(now>>(8*(3-j)))<<(8*(3-j));
}
}
return 0;
}
跑出來還是少了后面的一部分,考慮有對原始文本進行過 base64 隱寫,另寫腳本找出剩下的內容:
import base64
b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
with open('1.txt', 'rb') as f:
flag = ''
bin_str = ''
for line in f.readlines():
stegb64 = str(line, "utf-8").strip("\n")
rowb64 = str(base64.b64encode(base64.b64decode(stegb64)), "utf-8").strip("\n")
offset = abs(b64chars.index(stegb64.replace('=','')[-1]) - b64chars.index(rowb64.replace('=','')[-1]))
equalnum = stegb64.count('=') #no equalnum no offset
if equalnum:
bin_str += bin(offset)[2:].zfill(equalnum * 2)
print([chr(int(bin_str[i:i + 8], 2)) for i in range(0, len(bin_str), 8)])
拼接之后就是完整的 flag 了
flag{57735e0c-6d02-11ea-8072-040e3c032fa7}
sudo
沒有附件,可以遠程連接到數獨程序
一開始懷疑是盲打 pwn,手工輸入了長長的字符串,提示 invalid input! 沒有發生緩存區溢出
此外程序有個 alarm(),一小段時間無操作就會自動結束進程,這時候知道真的要做數獨了
(1~9)*81 的意思就是要輸入 81 個由數字 1~9 組成的字符,從上至下,從左至右填滿數獨棋盤
思路也比較簡單,用 pwntools 模塊收發信息,稍微進行清洗之后丟給(暴力)算法求解
exp 如下:
#coding=utf-8
from pwn import *
import datetime
payload = ''
class solution(object): # 數獨類,帶求解算法
def __init__(self,board):
self.b = board
self.t = 0
def check(self,x,y,value):
for row_item in self.b[x]:
if row_item == value:
return False
for row_all in self.b:
if row_all[y] == value:
return False
row,col=x/3*3,y/3*3
row3col3=self.b[row][col:col+3]+self.b[row+1][col:col+3]+self.b[row+2][col:col+3]
for row3col3_item in row3col3:
if row3col3_item == value:
return False
return True
def get_next(self,x,y):
for next_soulu in range(y+1,9):
if self.b[x][next_soulu] == 0:
return x,next_soulu
for row_n in range(x+1,9):
for col_n in range(0,9):
if self.b[row_n][col_n] == 0:
return row_n,col_n
return -1,-1
def try_it(self,x,y):
if self.b[x][y] == 0:
for i in range(1,10):
self.t+=1
if self.check(x,y,i):
self.b[x][y]=i
next_x,next_y=self.get_next(x,y)
if next_x == -1:
return True
else:
end=self.try_it(next_x,next_y)
if not end:
self.b[x][y] = 0
else:
return True
def start(self):
global payload
begin = datetime.datetime.now()
if self.b[0][0] == 0:
self.try_it(0,0)
else:
x,y=self.get_next(0,0)
self.try_it(x,y)
for i in self.b:
print i
for j in i:
payload += str(j)
end = datetime.datetime.now()
print '\ncost time:', end - begin
print 'times:',self.t
return
io = remote('47.93.204.245', '12000')
for i in range(3):
payload = ''
List = [[], [], [], [], [], [], [], [], []]
for i in range(9):
st = io.recvline()
st = st.replace('#', '0')
st = st.replace(' ', '')[:-1]
print st
for j in st:
List[i].append(int(j))
print List
s=solution(List)
s.start()
print 'payload: '+ payload
io.recvuntil('input your answer[ (1~9)*81 ]:\n')
io.sendline(payload)
#print io.recv()
#io.interactive()
io.recvuntil('Congratulation!')
io.interactive()