From 5342a74df7936d3e33f1d5c9b016986ccd340c0d Mon Sep 17 00:00:00 2001 From: Bernhard Neumann Date: Fri, 27 Dec 2019 01:12:29 +0100 Subject: [PATCH] Add writeup for Over the wire Advent Bonanza --- writeups/b3rn1/OTW_Advent19.md | 295 +++++++++++++++++++++++++++++++++ 1 file changed, 295 insertions(+) create mode 100644 writeups/b3rn1/OTW_Advent19.md diff --git a/writeups/b3rn1/OTW_Advent19.md b/writeups/b3rn1/OTW_Advent19.md new file mode 100644 index 0000000..9e716d9 --- /dev/null +++ b/writeups/b3rn1/OTW_Advent19.md @@ -0,0 +1,295 @@ +# Retrospective +I find the concept of CTF challenges as an advent calendar quite nice. However, I think the challeges should get easier since we have less time to solve the later challenges and that was in my opinion not really the case. Unfortunately, I didn't have much success with the challenges I played so I got a little frustrated after some time. + +# Challenges +## Northpole Airwaves [Unsolved] +### Description +During our latest expedition to the north pole, one of our scientists tuned her radio to 88Mhz and captured a slice of 1MHz (samplerate = 1M/s) to a GNURadio file sink. Surprisingly, there was more than just silence. We need your help to figure out what's going on. + +### Analysis +We were provided with a GNU radio file sink that functioned as the file source for a GNU radio flow chart. The first gnuradio flowchart that stiefel40k posted sounded like there was morse code in the otherwise random noise. Astra then got some audio tracks from the file with a FM Demod block in the gnuradio companion. I also played around a little with the blocks but couldn't reveal more than Astra already had. + +### Approaches +First approach by stiefel40k was to try if it was really morse code, he couldn't find anything meaningful. I also tried it myself but the track is really long so I didn't know where to look for the part for the flag. The beginning of the morse code is 414F54577B5468 which does not really look like a flag (or an hint where to find it), so I stopped there. Moreover, the audio tracks found by Astra looked (or sounded) more promising. So I also looked for the right track that is played there. stiefel40k found "Jesu, Joy of Man's Desiring" from Johann Sebastian Bach, which sounds quite similar but I think it is slightly different, however, that might just be because it is a different version. The name of the song wouldn't really help us as it was not the flag nor "Johann Sebastian Bach" or things alike. I thought maybe we need to find a radio station that plays classic, is far in the north and sends on 88 MHz but all I could find was a radio station in Alaska that sends on 88.1 (https://en.wikipedia.org/wiki/KBRW_(AM)). I tried their name and their call signs as the flag, which obviously didn't work. +stiefel40k had the idea that the flag was encoded in RDS (the data radio stations send out so the listener knows which radio station he is listening to and sometimes the song title). I therefore tried to decode the RDS with fm-rds which didn't work because there were blocks missing and I didn't know how to get them. Moreover, I tried gr-rds as well. After lots of installing dependencies the execution of the flowchart always finished with "ModuleNotFoundError: No module named 'rds'". Unfortunately, I did not find out how to get that module. stiefel40k managed to try it with gr-rds but couldn't get anything out of it. + +### Solution +The intended solution was a flag that was put together out of 3 parts. One was indeed RDS, one was indeed morse code and the third one used rc car based encoding. + +### Conclusion +I learned about gnuradio and how to use it in simple ways (probably too simple to find the flag). I think it would not be necessary to split the flag in 3 parts because it was already hard to find one of them. I spent about 12 hours on the challenge. + +## Musical Stegano [Solved] +### Description +I found a CD with some relaxing music on it, but one track just sounds completely off. The name of the track is 'BASS SEVEN TRIGRAPHS IN G MAJOR'. Hint: all the information you need to solve this challenge is audible. In other words, it's possible to solve with your ears only, though not everyone would be able to do that. An .ogg file is provided along with the .mid, for reference only, but is otherwise not useful. The .mid file is what you should use for the challenge. + +### Analysis +We are provided with a midi file and an ogg-file to listen to the music file. +Later they also published the music sheet as a pdf file and some hints: + +* If you don’t know music, it’s enough to know these concepts: + * Major scale: https://en.wikipedia.org/wiki/G_major + * How rhythm works, such as https://en.wikipedia.org/wiki/Eighth_note +* You do NOT need to know additional music theory such as chords. +* Both the treble and bass clefs are important. +* The challenge is tagged as a “stegano” but it’s actually very different from an image stegano - the point of an image stegano is to hide information in a way that does not affect the appearance of the image; this music stegano would sound different if the flag’s contents were changed. +* The flag format is AOTW{} and that wrapper part is embedded in the music as well. +* Consider it irrelevant whether a note is in the treble clef or the bass clef. For example, a middle C could be written on a treble clef (below the lines) or on a bass clef (above the lines) and they would sound exactly the same. When I said “don’t worry about chords”, I meant not to analyze the harmonic interactions between notes that play at the same time, not to ignore the bass clef (and treble clef can also have chords anyway). +* The way to encode notes in base 7 is: G = 0, A = 1, B = 2, ..., F# = 6. (If you don’t know what that # means, it does not matter; I’m just being technically accurate). +* The flag is spelled out chronologically, character by character, by special notes in the music, for some definition of “special”, but this definition can be described in just a few words. Non-special notes are irrelevant. + +### Approach +My first approach was to find the A of the AOTW part. Since we knew from the hint that the flag is base 7 encoded and the ASCII code for A is 65. 65 in base 7 is 122 and that is encoded in notes ABB. So I tried to find chords where these these 3 notes are played at the same time. However, I could not find it and the hint that chords don't really matter speaks against that as well. I then searched for ABB directly + +I also experimented a little with the python midi module but gained nothing useful from it. + +### Solution +The challenge was solved by ToasteR who found out that you have to take every second sixteenth note (no matter if in treble or in bass). The flag is AOTW{Mus1Cal_fUN}. + +### Conclusion +I learned a lot about musical steganography and a little bit about the midi python module. I find the concept of hiding a message in an musical piece highly interesting. I play the Flugelhorn in our local brass band but never have I thought of encoding messages in the music. I have spent around 3h on the challenge. + +## Naughty list +### Description +Santa has been abusing his power and is union busting us elves. Any elves caught participating in union related activities have been put on a naughty list, if you can get me off the list I will give you a flag. + +### Analysis +When entering the webpage we are provided with the following text: +``` +Naughty List + +You've been a naughty elf + +If you are here you have been a bad, bad elf. This holiday season, Santa has implemented a NO UNION policy in order to stay competitive with the likes of Amazon and AliExpress. We cannot afford to lose our competitive advantage due to your collective bargaining. + +Since you were caught attempting to participate in union related activities, you have been placed on a list for bad elves. Once on this list your Christmas related privileges have been revoked with immediate effect and you are now under a period of probation. + +In order to get off of this list, you will have to accumulate enough credits to show you are willing to participate in Christmas with the proper amount of Christmas spirit. Credits can be purchased with your hard earned gingerbread tokens in order to speed up your probation otherwise you will get a reduced wage of 1 gingerbread token per Christmas season (held in escrow). Once you have 5000 tokens, you can resume normal activities. + +Failure to meet these minimum demands will result in your entry to a re-education camp. +``` +We can now either navigate to the contact form, where we can submit a message or go to the login page, where we first have to register on the register page. After that we can now login with the credentials. + +Now a new tab appears where the username is shown and the credits (1/50000) and "next credit: expired". Below that there are 3 buttons to buy credits but all just have a JS as href where an alert pops up saying: "no privs". + +Below that there is an area to transfer credits to other elfs and a code. If we use the code given there we send the credit to santa. The code gets renewed every time we reload the page. The code is 59 characters long. We don't know our own code. + +If you click multiple times on "Account" or any other link apart from "Home" the value of the get parameter "page" always changes. The value has 54 characters and looks as if it is base64 encoded but can not be decoded. If you add anything to the parameter and hit enter a file not found error page is shown with the page parameter set to 404 and the from_page set to another base64 looking string but with length 139. + +Unfortunately, I was completely stuck there and didn't know what to do further. + +### Solution +First important thing that the others found out is, that you can use the from_page to encode data. To get to an the code of user "a" one had to use the page parameter as follows: ?page=anything:a. Then they created multiple users and made use of a race condition that occurred, and sent the credits back and forth until one user had more than 5000 credits. The flag was then AOTW{S4n7A_c4nT_hAv3_3lF-cOnTroL_wi7H0uT_eLf-d1sCipl1N3}. + +### Conclusion +The main challenge of this challenge was to guess the right way of adding the username to the page parameter to get the right token, which is not that appealing because its just guessing (and you couldn't even be sure, that it was about the page parameter). I spent around 3h on the challenge. + +## Snowflake Idle [Solved] +### Description +It's not just leprechauns that hide their gold at the end of the rainbow, elves hide their candy there too. + +### Analysis +First we are provided with an input field where we should enter our name and then click on the button "Start Adventure!". After that a cookie "id" is stored in the browser and we are on a board where we can see how many snowflakes we already have. Moreover one can collect snowflakes, melt snowflakes or buy a higher collection speed with snowflakes. Moreover if we have a vigintillion of snowflakes (10^63) we can buy the flag. One could also show the growth chart and erase the progress and start over new. When collecting a snowflake the board freezes for 1 second and we have to wait, that the snowflake is connected. + +After opening the network analysis of the browser we can see that there are the following endpoints are used: + +For each request the PHP session ID and the id cookies are sent in the header. + +/control POST-request with parameter "action": "new" and "name": "test" is used to register the new user "test" + +/client POST-request is used for more things. First of all with parameter "action": "collect" and "amount": 1 collects 1 snowflake for the current user, with parameter "action": "melt" 1 snowflake is melted and we can also retrieve the current state with the parameter "action": "state" that returns an object like +{"collect_speed":1,"elf_name":"test","snowflakes":0.0,"speed_upgrade_cost":11.0} + +/history/client GET-request returns the history of the commands on the server +like [[1577378430227,{"action":"state"}],[1577378599241,{"action":"state"}],[1577379556474,{"action":"state"}],[1577379567446,{"action":"state"}],[1577379604610,{"action":"state"}],[1577379616488,{"action":"collect","amount":1}],[1577379617921,{"action":"state"}],[1577380056401,{"action":"melt"}],[1577380057835,{"action":"state"}]] and it is used to draw the growth chart. + +### Approaches +First thing I tried was to set the amount directly with the parameter "amount". Unfortunately, the amount is ignored and the snowflakes are only increased by that amount that is currently legal for the user. Later we found out that the amount is used when drawing the snowflake growth chart. However even if you set the amount to 10^63 we are not provided with the flag, when drawing the graph. Here we also realised that any action is stored into the history, but we couldn't make any use of that. + +Another thing I tried, was to upgrade even if I'm not yet allowed to do so, but that didn't work as well, as that is also checked on the server. + +Because of the hint with the rainbow I thought that we maybe need to draw an rainbow on the chart and I tried it, but it is hard to draw a perfect rainbow and we would not now in which height to draw, so that would be way to ambigous. + +Therefore, we thought that the rainbow might suggest to look something up in a rainbow table. I tried the id and the PHP session id but without success. + +I also tried to manually collect the snowflakes, since the sleeping time is only done on the client (setTimeOut with 1000 milli seconds). However if you do that you get the error message "Throttled at one request per second. Please note that this challenge does NOT require brute forcing, and does NOT require sending an excessive number of requests." + +### Solution +The others found out that there is another endpoint /history/control by fuzzing (since /history/asdf didn't give a 404 Not Found they searched for an endpoint beneath history). The data that is returned looks like this [[1577378430227,{"action":"load"}],[1577378430227,{"action":"save","data":"6iq2Zm9wyq5DwLUQWXJ1whS6E031KuEpMDmTrheB6FtLZHXCE68FXLN1"}],[1577378599241,{"action":"load"}],[1577378599241,{"action":"save","data":"6iq2Zm9wyq5DwLUQWXJ1whS6E031KuEpMDmTrheB6FtLZHXCE68FXLN1"}], and the saved values change only sligthly. Therefore they concluded that this is the snowflake amount part. They changed it at the same byte and posted to /control with parameter "save" and could then buy the flag AOTW{leaKinG_3ndp0int5}. + +### Conclusion +I liked that challenge, because it was just one thing you had to find out not 3 like in day 3. However, I didn't like that you had to guess for the other endpoint (however, we could have thought about it, since we have got client, history/client and control, that there is also a hitory/control). I spent around 10 hours with the challenge. + +## Gr8 Escape [Unsolved] +### Description +The description was an imgur link to an image that shows a dialogue between a sun and his mom, where he asks if the elves also make the video games and she answers "sure" and than we see an elve struggling with C++ while reading a book "C++ for Dummies". + +### Analysis +When netcatting to the server we are provided with a colorful header "THE GR8 ESCAPE" and a prompt "game:" waiting for input. The server executable was also provided. I downloaded it and tried to decompile it. Therefore I tried to install Boomerang and Snowman, but that didn't work on my Ubuntu. Therefore I used the Snowman binary for Windows and decompiled it on Windows. The result was a C/C++ file with about 270 000 lines of code. In that file I searched for the string "game: " and found it once. From there I tried to understand along the code what can or should be done next but unfortunately I could not follow. +Code snippet: +``` + if (v9) { + fun_4117a0("game: ", rsi, rdx, rcx, r8, r9); + rax10 = fun_44bf60(0, v9, 0xe00, rcx, r8); + v11 = *reinterpret_cast(&rax10); +``` + +``` +void** fun_4117a0(void** rdi, void** rsi, void** rdx, void** rcx, void** r8, void** r9, ...) { + void** rsp7; + signed char al8; + void** rax9; + void** rdi10; + void** eax11; + uint64_t rcx12; + void** rax13; + void** rsp14; + void** rax15; + uint64_t rcx16; + void** rax17; + void** rsp18; + void** rax19; + void** r8_20; + void** rbx21; + void** rdx22; + void** eax23; + void* rsp24; + void** rsi25; + void** rdx26; + int1_t zf27; + int1_t zf28; + int1_t zf29; + int1_t zf30; + uint64_t rcx31; + void** rax32; + void* rsp33; + void** rsi34; + int1_t zf35; + void** rsp36; + void** r12_37; + void** r13_38; + void** rdi39; + void* rsp40; + void** rax41; + void* rsp42; + void** rax43; + void** r14_44; + void** rbx45; + uint32_t eax46; + void* rsp47; + void** rcx48; + void* rsp49; + int64_t* rsp50; + void** rax51; + void*** rsp52; + void** rax53; + void** rcx54; + void** rax55; + void* rsp56; + void** rcx57; + void*** rsp58; + void** rax59; + void*** rsp60; + void** rbx61; + void** rsp62; + void** rax63; + void** rdx64; + void** rdi65; + void** rsp66; + void** eax67; + void** rsp68; + void** rsi69; + void** rdx70; + int1_t zf71; + int1_t zf72; + int1_t zf73; + int1_t zf74; + void** rcx75; + int64_t* rsp76; + void** rsp77; + void** rax78; + void** rsp79; + void** rsp80; + void** rbx81; + void** rsp82; + void** rax83; + void** rbp84; + void** rdi85; + void** rsp86; + void** eax87; + void** rsp88; + int1_t zf89; + void** rsi90; + void** rdx91; + int1_t zf92; + uint64_t rcx93; + int64_t* rsp94; + void** rsp95; + void** rsp96; + void** rsp97; + void** rsp98; + void** eax99; + void** rsp100; + uint32_t edx101; + void** rsp102; + void** rdx103; + void** r8_104; + int1_t zf105; + int1_t zf106; + void** tmp32_107; + int1_t zf108; + void** tmp32_109; + void** rdx110; + int1_t zf111; + int64_t* rsp112; + void** r12_113; + void** rsp114; + void** rsp115; + void** rsp116; + void** r12_117; + void** rsi118; + int1_t zf119; + int1_t zf120; + int32_t tmp32_121; + int1_t zf122; + int32_t tmp32_123; + void** rsp124; + void** rdi125; + void** rsp126; + void** rdi127; + void** rsp128; + int1_t zf129; + int1_t zf130; + int64_t* rsp131; + int1_t zf132; + int1_t zf133; + int1_t zf134; + int1_t zf135; + int64_t* rsp136; + int64_t* rsp137; + void** rdx138; + void** r8_139; + int1_t zf140; + int1_t zf141; + int1_t zf142; + int64_t* rsp143; + int64_t* rsp144; + + rsp7 = reinterpret_cast(reinterpret_cast(__zero_stack_offset()) - 0xd8); + if (al8) { + __asm__("movaps [rsp+0x50], xmm0"); + __asm__("movaps [rsp+0x60], xmm1"); + __asm__("movaps [rsp+0x70], xmm2"); + __asm__("movaps [rsp+0x80], xmm3"); + __asm__("movaps [rsp+0x90], xmm4"); + __asm__("movaps [rsp+0xa0], xmm5"); + __asm__("movaps [rsp+0xb0], xmm6"); + __asm__("movaps [rsp+0xc0], xmm7"); + } +``` + +litplus later found out, that when entering some lines of "AAAAA..."s that it prints out a big dashed rectangle that has something like a progress bar on the top left corner. However it does not do that always. + +### Conclusion +I found that challenge really hard and frustrating because I did not know where to start. I spent around 4h on it. + -- 2.43.0