zoukankan      html  css  js  c++  java
  • 蓝帽杯2020 | 三题 MISC Writeup

    来自战队:@驴肉火烧

    签到

    附件下载

    题目给出一张图片,提示观色,预计可能是将信息隐藏在某一色道中或 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 了

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

  • 相关阅读:
    jQuery解析XML
    jQuery常用AJAX-API
    jQuery练习
    jQuery常用Event-API
    jQuery常用Method-API
    jQuery九类选择器
    js对象和jQuery对象的区别
    js对象和jQuery对象相互转换
    jQuery入门
    JSON
  • 原文地址:https://www.cnblogs.com/zhwer/p/13453465.html
Copyright © 2011-2022 走看看