来自战队:@驴肉火烧
签到
题目给出一张图片,提示观色,预计可能是将信息隐藏在某一色道中或 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("
")
rowb64 = str(base64.b64encode(base64.b64decode(stegb64)), "utf-8").strip("
")
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 '
cost 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 ]:
')
io.sendline(payload)
#print io.recv()
#io.interactive()
io.recvuntil('Congratulation!')
io.interactive()