蓝帽杯2020 | 三题 MISC Writeup

来自战队:@驴肉火烧python

签到

附件下载c++

题目给出一张图片,提示观色,预计多是将信息隐藏在某一色道中或 LSB 隐写
将给出的图片导入 StegSolve.jar,在 red plane 1 中发现半个 flag


算法

利用 Frame Browser 对图片进一步分析能够分离出第二张图片,数组

一样在 red plane 1 中发现另外半个 flag缓存

熟悉的解密

附件下载app

附件压缩包里面是一个文本文件,很明显是数行用 base64 编码的字符串ui

写以下脚本进行解码:编码

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() 双重加密获得五组由两个整数组成的列表spa

由内向外来看,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 了

base64 隐写原理

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()