HTB Stego write up for the Unprintable[INSANE] challenge

393 阅读2分钟

Unprintable

很头疼的一到题哈哈,基础分析都尝试无果。

解法

正方形,去解析每个小正方形的颜色,(0,0,0)->0 (255,255,255) ->1 转换成二进制

实验出10个像素点是一个小正方形,写两个loop读取到一串二进制字符串

from PIL import Image


def generate_binary_string():
    try:
        img = Image.open("Unprintable.png")  # Open the img
    except:
        print('Put Unprintable.png file on this directory')
        exit(1)

    pixels = img.convert('RGB')  # Convert it in RGB

    width, height = img.size  # Getting the img's dimension

    binary_string = ""

    # Loop every 10 pixels
    for y in range(0, height, 10):
        for x in range(0, width, 10):

            r, g, b = pixels.getpixel((x, y))
            
            if r == g == b == 0:  # If the pixel is 0 = black = 0
                binary_string += "0"
            elif r == g == b == 255:  # If the pixel is 255 = white = 1
                binary_string += "1"

    return binary_string

之后将二进制转为ASCII码看看有没有有用的信息,每八位提取出来。

def bitstring_to_bytes(s):
    v = int(s, 2)
    b = bytearray()
    while v:
        b.append(v & 0xff)
        v >>= 8
    return bytes(b[::-1])


def to_ascii(binary_string):

    binary_values = [binary_string[i:i+8] for i in range(0, len(binary_string), 8)]
    raw_str = ""
    for i in range(len(binary_values)):
        bs = bitstring_to_bytes(binary_values[i])
        raw_str += str(bs).replace("b'","").replace("'","")

    return raw_str
    
    
if __name__ == '__main__':
    binary_string = generate_binary_string()
    print(to_ascii(binary_string))


#  to_ascii中参数为#0010110101011011001101110010110100111110001010110011110001011101001111100010110...
#输出为
#-[7->+<]>-.\x88[3\x83+\x86>-.[5\x83+\x86>2-.4\x80\x832+\x86\x8.\x80\x8e5+\x90>+.\x802\x8e+\x86\x88.[5\x83+\x90>3-.3+.2+.\x8[5\x83+\x86>.2\x803\x8e2+\x86>3

发现有很多\x88 \x83的东西,它是 RLE 编码的brainfuck,参考谷歌找到对于的编码

将 \x88 替换成 >-

将 \x83 替换成 ->

将 \x86 替换成 <]

将 \x80 替换成 -[

将 \x8 替换成 >-

将 \x90 替换成 <]

将 -e 和以及前面的一个字节替换成 -> 例如 >-e 替换成 ->

最终得到

-[7->+<]>-.>-[3->+<]>-.[5->+<]>2-.4-[->2+<]>-.-[->5+<]>+.-[2->+<]>-.[5->+<]>3-.3+.2+.>-[5->+<]>.2-[3->2+<]>3-..>-[5->+<]>.-[->2+<]>.5-.13-.6-.-[3->2+<]>+.3-[->2+<]>-.3+.[3->+<]>4-.[2->+<]>5-.3-.-[5->+<]>2-.8-.-[3->+<]>2-.+[->3+<]>+.8+.12-.+[2->+<]>+.[3->2+<]>3-.2+[->3+<]>.15+.2+[->5+<]>.2-[3->2+<]>.+[->3+<]>.7+.-[3->+<]>2-.7-.[3->+<]>3+.

这就是一个RLE压缩了,将他进行恢复,例如7- 就代表------- , 2+就代表++ 以此类推

def rle_decode(decoded_str):
    final_decoded_string = ""
    i = 0
    while i < len(decoded_str):
        if decoded_str[i].isdigit():
            if decoded_str[i + 1].isdigit():
                final_decoded_string += int(decoded_str[i] + decoded_str[i + 1]) * decoded_str[i + 2]
                i += 3
            else:
                final_decoded_string += int(decoded_str[i]) * decoded_str[i + 1]
                i += 2
        else:
            final_decoded_string += decoded_str[i]
            i += 1
    return final_decoded_string

最终得到

-[------->+<]>-.>-[--->+<]>-.[----->+<]>--.----[->++<]>-.-[->+++++<]>+.-[-->+<]>-.[----->+<]>---.+++.++.>-[----->+<]>.--[--->++<]>---..>-[----->+<]>.-[->++<]>.-----.-------------.------.-[--->++<]>+.---[->++<]>-.+++.[--->+<]>----.[-->+<]>-----.---.-[----->+<]>--.--------.-[--->+<]>--.+[->+++<]>+.++++++++.------------.+[-->+<]>+.[--->++<]>---.++[->+++<]>.+++++++++++++++.++[->+++++<]>.--[--->++<]>.+[->+++<]>.+++++++.-[--->+<]>--.-------.[--->+<]>+++.

bf编码进行解密即可得到flag

完整代码:

# !/usr/bin/env python3

from PIL import Image


def bitstring_to_bytes(s):
    v = int(s, 2)
    b = bytearray()
    while v:
        b.append(v & 0xff)
        v >>= 8
    return bytes(b[::-1])


def get_replace(binary_values,bs,next=False):
    index = int.from_bytes(bs, "little") - 128
    if(next):
        _bs = bitstring_to_bytes(binary_values[index + 1])
    else:
        _bs = bitstring_to_bytes(binary_values[index])
    return _bs


def generate_binary_string():
    try:
        img = Image.open("Unprintable.png") # Open the img
    except:
        print('Put Unprintable.png file on this directory')
        exit(1)

    pixels = img.convert('RGB') #Convert it in RGB

    width, height = img.size    #Getting the img's dimension

    binary_string = ""

    # Loop every 10 pixels
    for y in range(0, height, 10):
        for x in range(0, width, 10):

            r, g, b = pixels.getpixel((x, y))

            if r == g == b == 0:    #If the pixel is 0 = black = 0
                binary_string += "0"
            elif r == g == b == 255:    #If the pixel is 255 = white = 1
                binary_string += "1"

    return binary_string


def decode_binary(binary_string):

    binary_values = [binary_string[i:i+8] for i in range(0, len(binary_string), 8)]

    decoded_str = ""
    raw_str=""
    for i in range(len(binary_values)):
        bs = bitstring_to_bytes(binary_values[i])
        raw_str += str(bs).replace("b'","").replace("'","")
        try:
            decoded_str += bs.decode()
        except:
            _bs = get_replace(binary_values,bs)
            try:
                decoded_str += _bs.decode()
            except:
                __bs = get_replace(binary_values, _bs)
                decoded_str += __bs.decode()
                __bs = get_replace(binary_values, _bs, True)
                decoded_str += __bs.decode()
                continue
            _bs = get_replace(binary_values, bs, True)
            try:
                decoded_str += _bs.decode()
            except:
                __bs = get_replace(binary_values, _bs)
                decoded_str += __bs.decode()
                __bs = get_replace(binary_values, _bs, True)
                decoded_str += __bs.decode()
    print("The raw decoded string is:\n" + raw_str )
    return decoded_str


def rle_decode(decoded_str):
    final_decoded_string = ""
    i = 0
    while i < len(decoded_str):
        if decoded_str[i].isdigit():
            if decoded_str[i + 1].isdigit():
                final_decoded_string += int(decoded_str[i] + decoded_str[i + 1]) * decoded_str[i + 2]
                i += 3
            else:
                final_decoded_string += int(decoded_str[i]) * decoded_str[i + 1]
                i += 2
        else:
            final_decoded_string += decoded_str[i]
            i += 1
    return final_decoded_string



if __name__ == "__main__":

    binary_string = generate_binary_string()
    print("The binary string is:\n" + binary_string)
    decode_binary = decode_binary(binary_string)
    print("The binary string properly decoded is: \n" + decode_binary)
    final_decoded_string = rle_decode(decode_binary)
    print("The brainfuck string is: \n" + final_decoded_string)

bf解密

ctf.bugku.com/tool/brainf…