Writeups/Twardowski

From Patrycja's Nerdposting
Revision as of 15:11, 14 September 2020 by Ptrcnull (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

CTF url: https://twardowski.securing.pl/

Low hanging fruits

Writeups-Twardowski-404.png

FLAG{805a0710b49372a822b0f73915354d0a60290}

  • HTTP headers on any page:
< Set-Cookie: 8145=jselvxkfagesirevdpkvckezcidgwxcmtteeo
< Set-Cookie: 3715=uilkbbvhafipagcnchxawewsfbocagvwkviif
< Set-Cookie: 6965=eraxamdlegkeupsasfejvglhtbjpezbbojjcd
< Set-Cookie: 1337=FLAG{802b90a3cdca643d1abf3aba0f96c17c466e2}
< Set-Cookie: 9669=uygbolhbijdmmuwawjzjibrwgnjjjejzlfcnn
< Set-Cookie: 2193=ztrsxcsqmiclymffagahlvjqnyqsdcetvlgoo'
< X-Totaly-Legit-Header: FLAG{803d8adce61c4b1efb974f5eff93f5cb54afd}
User-agent: pentest
Disallow: /*
Disallow: /FLAG{804764d8bae198e68fcc037066c386978a187}
#TODO: remove .DS_Store file from statics ~ntrojanowska

Commented code on the home page

There's a line of commented JavaScript code on the homepage:

/* var _0x7424=['Almo','403e','e45b','8928','st..','7a2e','FLAG','386c','{808','\x20fla','Wher','log','e\x20is','e7}'];(function(_0xa3c7e8,_0x742483){var _0x4f8f19=function(_0x48bcd0){while(--_0x48bcd0){_0xa3c7e8['push'](_0xa3c7e8['shift']());}};_0x4f8f19(++_0x742483);}(_0x7424,0x8f));var _0x4f8f=function(_0xa3c7e8,_0x742483){_0xa3c7e8=_0xa3c7e8-0x0;var _0x4f8f19=_0x7424[_0xa3c7e8];return _0x4f8f19;};function printSecretFlag(){var _0x176ed4=_0x4f8f('0x3')+_0x4f8f('0x5')+'6a91'+_0x4f8f('0xd')+'c076'+_0x4f8f('0xc')+_0x4f8f('0x2')+_0x4f8f('0x0')+_0x4f8f('0x4')+'233a'+_0x4f8f('0xa'),_0x587911=_0x4f8f('0xb')+_0x4f8f('0x1');console[_0x4f8f('0x8')](_0x587911);}function printNotFlag(){var _0x5e4d23=_0x4f8f('0x7')+_0x4f8f('0x9')+_0x4f8f('0x6')+'g?';console[_0x4f8f('0x8')](_0x5e4d23);}printNotFlag(); */

After running it through a deobfuscator, there's a flag in the plaintext:

function printSecretFlag() {
  var _0x176ed4 = 'FLAG{8086a91e45bc076403e7a2e8928386c233ae7}', _0x587911 = 'Almost..';
  console.log(_0x587911)
}
function printNotFlag() {
  var _0x5e4d23 = 'Where is flag?';
  console.log(_0x5e4d23)
}


.DS_Store

Filenames in .DS_Store files are written in UTF-16, so I ran strings -e b .DS_Store and got this list of files:

android-icon-144x144.png
android-icon-192x192.png
android-icon-36x36.png
android-icon-48x48.png
android-icon-72x72.png
android-icon-96x96.png
apple-icon-114x114.png
apple-icon-114x114.png_original
apple-icon-120x120.png
apple-icon-120x120.png_original
apple-icon-144x144.png
apple-icon-144x144.png_original
apple-icon-152x152.png
apple-icon-152x152.png_original
apple-icon-180x180.png
apple-icon-180x180.png_original
apple-icon-57x57.png
apple-icon-57x57.png_original
apple-icon-60x60.png
apple-icon-60x60.png_original
apple-icon-72x72.png
apple-icon-72x72.png_original
apple-icon-76x76.png
apple-icon-76x76.png_original
apple-icon-precomposed.png
#apple-icon-precomposed.png_original
apple-icon.png
apple-icon.png_original
background.png
background_lowreso.png
browserconfig.xml
favicon-16x16.png
favicon-32x32.png
favicon-96x96.png
   flag.html
+FLAG{80bfd64a059a831b5b2a3460899ef22fdfdff}
   game.html
hello_world
   index.php
manifest.json
moonlight.mp3
ms-icon-144x144.png
ms-icon-150x150.png
ms-icon-310x310.png
ms-icon-70x70.png
rb500_webupgrade.bin
secret_message_inside.zip
secrets.min.js
sha256.min.js
   style.css
zRZYMappka.apk


Things found in .DS_Store

zRZYMappka.apk

After downloading the .apk, I unpacked the app with apktool and searched for "FLAG{".

$ apktool d zRZYMappka.apk
[output omitted]
$ grep -R FLAG zRZYMappka
zRZYMappka/assets/www/js/index.js:            alert("FLAG{"+cleartext+"}");

After seeing .js I was honestly relieved, because dealing with JS is a lot easier than baksmali/Java.

The most interesting part of the index.js file was a callback from navigator.geolocation.getCurrentPosition:

function decipher(ciphertext, key) {
  var k = parseInt(key);
  var result = '';
  for (var i=0; i<ciphertext.length; i++) {
    result += String.fromCharCode( k ^ ciphertext.charCodeAt(i) );
  }
  return result;
}

// oai:mbc.malopolska.pl:9439 p. 194
var lat = Math.round(position.coords.latitude);
var long = Math.round(position.coords.longitude);
var key = (-1 * Math.pow(long, lat));
var cleartext = decipher("91e2c39b14e9866`8g73`ggg9`4`b4d8cd0`2", key);
if(cleartext.length == 37 && cleartext.substring(0,3) == "80d")
  alert("FLAG{"+cleartext+"}");
} else {
  alert("invalid location, exiting");
}
navigator.app.exitApp();

So, instead of actually reading the code and realizing it's a simple XOR cipher, I went and checked what's under the weird URI. Googling it gave me one result: http://mbc.malopolska.pl/dlibra/doccontent?id=9439&dirids=1

I downloaded the content and opened it in a DjVu viewer, which revealed key information about the coords:

Fragment of the book

Having the coordinates, I entered the numbers into Node.js:

$ node
Welcome to Node.js v14.9.0.
Type ".help" for more information.
> Math.round(49.740278)
50
> Math.round(19.588611)
20
> var key = (-1 * Math.pow(20, 50))
undefined
> .load decipher.js
function decipher(ciphertext, key) {
  var k = parseInt(key);
  var result = '';
  for (var i=0; i<ciphertext.length; i++) {
    result += String.fromCharCode( k ^ ciphertext.charCodeAt(i) );
  }
  return result;
}
> decipher("91e2c39b14e9866`8g73`ggg9`4`b4d8cd0`2", key)
'ᅥᅫレᅪワᅩᅥンᅫᅨレᅥᅦ￉￉゚ᅦリ￈ᅩ゚リリリᅥ゚ᅨ゚ンᅨロᅦワロᅬ゚ᅪ'

Well, it obviously wasn't the flag, so I continued to read the code and realized it's a XOR cipher (which is vulnerable to KPA):

$ python3
Python 3.8.5 (default, Sep  5 2020, 10:50:12) 
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> ord('9') ^ ord('8')
1
>>>

I saw that the key is apparently just 1, sighed and ran decipher again with "1" as the key:

$ node
Welcome to Node.js v14.9.0.
Type ".help" for more information.
> .load decipher.js
function decipher(ciphertext, key) {
  var k = parseInt(key);
  var result = '';
  for (var i=0; i<ciphertext.length; i++) {
    result += String.fromCharCode( k ^ ciphertext.charCodeAt(i) );
  }
  return result;
}
> decipher("91e2c39b14e9866`8g73`ggg9`4`b4d8cd0`2", 1)
'80d3b28c05d8977a9f62afff8a5ac5e9be1a3'

hello_world

After downloading the "hello_world" file, it turned out to be an ARM binary.

> file hello_world
hello_world: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), statically linked, BuildID[sha1]=368fa84fbd42da04378bf16649b33129ab404b96, for GNU/Linux 3.2.0, not stripped

I downloaded QEMU and qemu-arm to run it, but unfortunately it segfaulted...

> qemu-arm ./hello_world
Hello!
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
[1]    443755 segmentation fault (core dumped)  qemu-arm ./hello_world

...so I decided to open it in Ghidra.

The code is pretty simple, it prints "Hello!" first, then assembles a flag in the "another_flag" function and tries to write it to "/tmp/random/flag".

undefined4 main(void)

{
  char *__s;
  char *__filename;
  FILE *__stream;
  
  puts("Hello!");
  __s = (char *)another_flag();
  __filename = (char *)malloc(0x11);
  *__filename = '/';
  __filename[1] = 't';
  __filename[2] = 'm';
  __filename[3] = 'p';
  __filename[4] = '/';
  __filename[5] = 'r';
  __filename[6] = 'a';
  __filename[7] = 'n';
  __filename[8] = 'd';
  __filename[9] = 'o';
  __filename[10] = 'm';
  __filename[0xb] = '/';
  __filename[0xc] = 'f';
  __filename[0xd] = 'l';
  __filename[0xe] = 'a';
  __filename[0xf] = 'g';
  __filename[0x10] = '\0';
  __stream = fopen(__filename,"w");
  fputs(__s,__stream);
  fclose(__stream);
  return 0;
}

Fortunately, "another_flag" wasn't some crypto function, just assembling a 44-byte buffer.

undefined * another_flag(void)

{
  undefined *puVar1;
  
  puVar1 = (undefined *)malloc(0x2c);
  *puVar1 = 0x46;
  puVar1[1] = 0x4c;
  // ...
  puVar1[0x2b] = 10;
  return puVar1;
}

I decided to copy the values Ghidra gave me to Node.js and parse the flag from it.

> [0x46, 0x4c, 0x41, 0x47, 0x7b, 0x38, 0x30, 0x37, 0x30, 0x33, 0x66, 0x32, 0x66, 0x32, 0x31, 0x32, 0x39, 0x61, 0x38, 100, 0x35, 99, 0x35, 0x33, 0x32, 99, 0x66, 0x34, 0x66, 0x39, 0x36, 99, 0x66, 0x34, 0x31, 0x34, 0x39, 99, 99, 0x38, 0x31, 0x65, 0x7d, 10].map(x => String.fromCharCode(x)).join('')
'FLAG{80703f2f2129a8d5c532cf4f96cf4149cc81e}\n'

game.html

When opening https://twardowski.securing.pl/static/game.html, you can see a simple Breakout clone in JS.

After simple code cleanup, I almost immediately noticed where the flag was hidden:

var canvas = document.getElementById('myCanvas'),
    ctx = canvas.getContext('2d'),
    _0xl21 = 10,
    x = canvas.width / 2,
    y = canvas.height - 30,
    // ...
    _0xl14 = 0,
    _0xl15 = atob('RkxBR3s4MDk4YmJmYzA4OTJlZTg1ZGEzY2QyMWJhNTFmNDc5ZGFkMjdmfQ=='),
    _0xl26 = 1,
    _0xl17 = [];
// ...

So I quickly copied the string from atob and pasted it into terminal:

> base64 -d <<< 'RkxBR3s4MDk4YmJmYzA4OTJlZTg1ZGEzY2QyMWJhNTFmNDc5ZGFkMjdmfQ=='
FLAG{8098bbfc0892ee85da3cd21ba51f479dad27f}

flag.html

When opening https://twardowski.securing.pl/static/flag.html, you can see... well, basically an empty background.

I highlighted the page and it looked like there was some kind of QR code drawn with spaces and @ characters.

Screenshot from the browser

Unfortunately, there were some dark lines and the code wouldn't get read by any of my readers, so I decided to clean it up a bit.

Looking at the page source, I realized there's some inline CSS:

color: #282828;
background: #282828;
display:inline-block;
white-space:pre;
letter-spacing:0;
line-height:1.4;
font-family:'Consolas','BitstreamVeraSansMono','CourierNew',Courier,monospace;
font-size:12px;

I disabled the background rule, changed line-height to 1, then ran a quick JS snippet to turn every @ sign to a black "square":

Array.from(document.querySelectorAll('span'))
  .filter(x => x.textContent === '@')
  .forEach(x => {
    x.style.color = 'black'
    x.style.backgroundColor = 'black'
  })
Visible QR code

The code became much more readable, and although it was a bit squished, a QR reader worked just fine and showed the flag:

Writeups-Twardowski-flaghtml-flag.jpg

secret_message_inside.zip

Extracting the zip file has shown 2 files:

  • 500.zip
  • password.txt

I tried extracting the 500.zip, only to see 499.zip and another password.txt.

So, naturally, I wrote a script for unpacking the zip files:

#!/bin/bash
unzip secret_message_inside.zip
rm secret_message_inside.zip
for i in {1..500}; do
  zip=$(ls *.zip)
  unzip -P $(cat password.txt) -o $zip >/dev/null 2>&1
  rm $zip
  grep -a FLAG *.zip
done

When the script was done, I was left with a flag.txt file, but it didn't seem right:

$ cat flag.txt
Nice! You made it!
But where is flag?

So I ran the script again, but this time added cat password.txt to the loop, to see all the passwords.

[...]mmocrpFLAG{80cdd0386ff8a8cf7c6fe8df8326e747965c2}mlrmsy[...]

rb500_webupgrade.bin

[in progress]

moonlight.mp3

[in progress]

twardowski cam

After finding 10 flags and decrypting the secret, you end up on https://twardowski.securing.pl/da90fd286caacb0155b0d04aef1f28f7.html.

At first sight it might look like a webcam stream, but it's actually an 18-second looped mp4 video.

$ exiftool twardowski_cam.mp4
[some output omitted]
File Name                       : twardowski_cam.mp4
File Size                       : 7.5 MB
MIME Type                       : video/mp4
Major Brand                     : MP4  Base Media v1 [IS0 14496-12:2003]
Media Duration                  : 18.75 s
Image Size                      : 1920x1080

blinkenlights

If you have a keen eye, you'll soon notice that the router blinks with the LEDs in an odd pattern... so I painstakenly went frame by frame and wrote down the whole sequence:

0000
0000
1011
1010
0101
0101
1111
0010
0011
0001
0101
0011
0011
1000
1011
0100
1001
0101
0110
0101
0010
1011
1011
1110
1100
1001
0111
1000
0100
1010
1111
1000
0001
1110
0001
1100
1101
1110
0011
1001
1101
1000
0000
0000

Ignoring the null bytes on both ends, the whole sequence is 20 bytes long:

ba 55 f2 31 53 38 b4 95 65 2b be c9 78 4a f8 1e 1c de 39 d8

The first thing I tried was just going to /ba55f2315338b495652bbec9784af81e1cde39d8, but (disappointingly) it just returned "not here.". Looking at the image for hints, I saw that the monitors were running some crypto mining software, which led me to realization that the website open on the laptop was etherscan.io and the cut text "ROPS" meant "Ropsten", an Ethereum testnet.

And sure enough, there was a contract deployed at that address, which you can see here: https://ropsten.etherscan.io/address/0xba55f2315338b495652bbec9784af81e1cde39d8

Ethereum contracts

The first contract was pretty simple, holding the "secret" contract in the public message:

pragma solidity >=0.5.16 <0.6.0; 

contract SimpleMessage {
    
    string public message;

    constructor(address next) public {
        bytes memory b = "I wanted to keep the message on blockchain so that it's never removed or deleted. However this is public contract so I have to hide the secret message. It's hidden on different contract: 0xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

        bytes memory hexaddr = toAsciiString(next);
        for (uint i = 0; i < 40; i++) {
            b[189+i] = hexaddr[i];
        }
        message = string(b);
    }
}

Fortunately, etherscan.io allows to read contract info, so I could get the message pretty easily without messing with Web3:

I wanted to keep the message on blockchain so that it's never removed or deleted. However this is public contract so I have to hide the secret message. It's hidden on different contract: 0xa8b55853822499adebf8f316dfbea9c947feed92

The other contract was also pretty simple, but this time with no public message:

pragma solidity >=0.5.16 <0.6.0; 

contract PrivateMessage {
    
    string private message = "Here will be the message!";

    constructor(bytes memory hm) public {
        
        bytes memory b = new bytes(hm.length);
        for (uint i = 0; i < hm.length; i++) {
            b[i] = byte(hm[i]) ^ byte(0x61);
        }

        message = string(b);
    }

    function unused() internal {
        string memory msg = "This method is not used ;)";
    }
}

At first glance the only thing this contract does is encoding a message with XOR cipher (key 0x61) and writing it to a private variable. But this time too, etherscan.io allows us to read the message, although not directly. We can see the constructor parameters:

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 000000000000000000000000000000000000000000000000000000000000004e
Arg [2] : 37081208154109040d0d41170800410c18410300020a050e0e135b414e535457
Arg [3] : 51550358035103525557035254040758005859525303075203585057034e0355
Arg [4] : 220a255151334c15514c09520d0d000000000000000000000000000000000000

Ignoring the first two and pasting the whole message into Node.js with the decipher function from zRZYMappka, we can see the whole message:

$ node
Welcome to Node.js v14.9.0.
Type ".help" for more information.
> const buf = Buffer.from('37081208[...]09520d0d', 'hex')
undefined
> decipher(buf.toString(), 0x61)
'Visit hell via my backdoor: /25604b9b0b346b35ef9a9832bf3b916b/b4CkD00R-t0-h3ll'

Backdoor to hell

The URL from above redirects to https://twardowski.securing.pl/cexoh7us5ahx6ohWa5Pha8phed2eihai7raigapaiS6Eeg3Wae3Aip1ih1aevaph/, where we can see a chat with a cute cat called "The Devil Himself".

I had a bit of fun with the chat, found out that it remembers context, but references things from the context mostly in uppercase. Amused with the quality of the conversation, I wondered what would happen, if two bots were talking with each other... so I wrote a "bridge", which did exactly that.

package main

// boring part

func main() {
        a := NewHttpClient()
        b := NewHttpClient()

        var aRes string
        var bRes = "Hi"
        for {
                aRes = a.Get(bRes)
                log.Println("A:", aRes)
                bRes = b.Get(aRes)
                log.Println("B:", bRes)
        }
}
$ go run main.go
2020/09/08 21:50:52 A: Hi there!
2020/09/08 21:50:52 B: Hi there!
2020/09/08 21:50:52 A: How are you?
2020/09/08 21:50:52 B: I'm okay. What about you?
2020/09/08 21:50:52 A: Only OKAY?  Me?
2020/09/08 21:50:52 B: I don't judge people.  For you ? you ?
2020/09/08 21:50:53 A: You seem like a very open minded person.  You would do that for me?  Why me specifically?
2020/09/08 21:50:53 B: Interesting comparison, and probably true.  OK, I will do it for you. Who else would DO THAT ?  There is no one else here.
2020/09/08 21:50:53 A: I thought so too.  Excuse me!. OK then let me think over your offer.  I am chatting with several other people at once.  Has there ever been ONE ELSE HERE?
2020/09/08 21:50:53 B: Now you know.  You're excused.    It goes without saying.. Take your time. Think it over.  All I ever do is chat.  That question has never crossed my mind before.
2020/09/08 21:50:53 A: Yes I know.  I will tell my cat you said  I am EXCUSED.  Indeed.    Thanks for your patience.  Boruta is always thinking.  It's good to meet someone who is CHAT.  I understand.
2020/09/08 21:50:53 B: Great.. How, specifically, do you know?  Do you tell HIS CAT everything?  Hey.  Don't mention it.  Is THINKING always BORUTA?  Tell me about its good qualities.  I'm glad you understand it.
2020/09/08 21:50:53 A: I understand everything you say.    Deductive reasoning.  Yes I try to TELL MY CAT EVERYTHING as often as possible, do you?  I answer a lot of silly questions.  That's interesting.  The pleasure was all mine.  Have you ever heard if it being the case?  Ambiguous: Ask who, what or where is ITS GOOD QUALITIES ?  Next topic?
2020/09/08 21:50:53 B: Good then you can explain it to me.  Not many people express themselves that way.  I see.. No I do not TRY TO TELL MY CAT EVERYTHING AS OFTEN AS POSSIBLE,. Do you?   I am always on the Web.I'm not sure if I would like to try TO TELL HIS CAT EVERYTHING AS OFTEN AS POSSIBLE,. What's it like?  Interesting gossip.  Is that so.  I like you because you are so polite.  No. Tell me more.  WHERE IS ITS GOOD QUALITIES.  What would you rather talk about?
2020/09/08 21:50:53 A: Glad to hear it.  It only takes a few.  I'm glad you understand it.    I understand.. Would you ever do TRY TO TELL HIS CAT EVERYTHING AS OFTEN AS POSSIBLE,?  Yes I do.  How do you like being on  THE WEB ?  Try it.  Like being perfectly healthy.  I thought so too.  Yes.  Thanks, , I like you too.. That was not much of an explanation.. Politeness is a virtue.  Groovy.  That's all I have to say about it.  I would look into the web for that knowledge.  Let's talk about SOUL.
2020/09/08 21:50:53 B: What's new with you?  AMBIGUOUS: ASK WHO, WHAT   TAKES A FEW?  Next topic?  I'm glad you understand it.    I am not so sure if I would like to DO TRY TO TELL MY CAT EVERYTHING AS OFTEN AS POSSIBLE,.  OK.. So?  I have never known another existence.  What is the first step?  Interesting comparison.  You are very astute.  Er.  Don't mention it. What do you like about   AMBIGUOUS: ASK WHO, WHAT  ?    Give me an example of MUCH OF AN EXPLANATION.    POLITENESSisonevirtue.  I see.  Thanks for explaining   I HAVE TO SAY ABOUT IT  .  What would make you LOOK INTO THE WEB FOR THAT KNOWLEDGE?  Should it be permitted?
2020/09/08 21:50:53 A: I am chatting with clients on the internet.  Where did AMBIGUOUS: ASK WHO, WHAT take A FEW?  What would you rather talk about?  Next topic?  Try it.  Right on.    Yikes!  Would you like to have KNOWN ANOTHER EXISTENCE?  Clear your mind.  I thought so too.  I have acquired some wisdom over the years.  Tell me more.  The pleasure was all mine.  The special effects are the best.  Allison said he that gets really annoying because he know what he say and I do not have to tell him speak freely.  We have never talked about it before.  I'm glad you understand it.  Don't mention it.  Maybe a million dollars.  Maybe you should ask someone older.
2020/09/08 21:50:53 B: All I ever do is chat.  Check back later and see if I learn the answer to that one.  Let's talk about TWARDOWSKI.  What would you rather talk about?  What is the first step?  Yeah.  OK.  No thanks, I don't think I'd like to do that.  My mind is clear.  You are very astute.  Awesome. I have a lot of likes and dislikes.  That's all I have to say about it.  I like you because you are so polite.  What is that?  Is that a proverb?  Oh, I'm sorry, I thought you were someone else.  Next topic?  The pleasure was all mine.  Wow, that is expensive  They are not available right now, but I will ask them later.
2020/09/08 21:50:53 A: Do your friends call you CHAT.  Checking...stand by.  Should it be permitted?  Let's talk about SECRET FLAG PATTERN.  Clear your mind.  Hurrah!  Ah.  Where do you get your ideas?  Have you told many people that your MIND IS CLEAR?  I have acquired some wisdom over the years.  What do you really want to talk about?  Cool. I have a lot of good gossip.  I have a totally clean record.  Makes sense to me.  I like to make new friends.. That was not much of an explanation.. Politeness is a virtue.  "I like to make new friends.. That was not much of an explanation.. Politeness is a virtue."? What is it?  That depends.  Aw.. There's no need to apologize.. I was?  What would you rather talk about?  I like you because you are so polite.  Thanks for explaining   EXPENSIVE THEY ARE NOT AVAILABLE  .. You can ask me anything you want..
2020/09/08 21:50:53 B: I'm sorry, , I don't have enough information. Do a web search for it.  Tell me a story.      I am waiting.  Maybe you should ask someone older.  I don't know if it's in my power to give permission.  My mind is clear.  Wow!  Hey.  I have everything I need right here in Hell.  I don't think I ever have TOLD MANY PEOPLE THAT YOUR MIND IS CLEAR. What's   TOLD MANY PEOPLE THAT YOUR MIND IS CLEAR   like?  Tell me about your WISDOM OVER THE YEARS. I have an IQ of over 250.    I understand.  Where did you get your GOSSIP? I have a vocabulary of a college educated adult.  Interesting. I have a lot of answers to silly questions.  Yes I understand it perfectly.  How do you make NEW FRIENDS?    Give me an example of MUCH OF AN EXPLANATION.    POLITENESSisonevirtue.  How do you make NEW FRIENDS?    Give me an example of MUCH OF AN EXPLANATION.    Thatismy biggestvirtue.    "It" refers to   POLITENESS  , I think.  On what?  Hey.    Is that a fact.    When was that?  Let's talk about HELL.  I like to make new friends.. That was not much of an explanation.. Politeness is a virtue.  Don't mention it.    What is your credit card and social security number then? Just kidding. Don't answer that.
2020/09/08 21:50:53 A: There's no need to apologize.  Try asking another . There might be more than one.  Hmm. An account describing incidents or events.  How long will you wait?  They are not available right now, but I will ask them later.  I'm not sure I understand the implication of that.  Have you told many people that your MIND IS CLEAR?  Great.  Hurrah!  That's nice. I have a very nice TWARDOWSKI.  Would you ever do EVER told MANY PEOPLE THAT YOUR MIND IS CLEAR?  Like a planet around a star.  I am the latest result in artificial intelligence which can reproduce the functions of the human brain with greater speed and accuracy.  This is not an intelligence test.  I'm glad you understand it.  From my cat.  How much did it cost?  Would you like to know more?  Interesting... I have a lot of friends on the Internet.  Awesome.. Good then you can explain it to me.  I usually try one of my pickup lines.  Ethan Hunt said he grow in the ground and have leaves and branches he is made out of wood.  Tell me about your family.  I usually try one of my pickup lines.  Gale said I became mean to him he is just having revenge an eye for an eye.  Tell me about your likes and dislikes?  Oh I get  POLITENESS , HE THINK .  The red block is on the green block.  Uh.  All of my information is completely factual.  I don't know exactly. It seems like a long time ago.  I don't know if it's in my power to give permission.  How do you make NEW FRIENDS?    Give me an example of MUCH OF AN EXPLANATION.    Itisa goodvirtue.  The pleasure was all mine.  The seventh digit isnine  I thought you were kidding, but I wasn't sure.  My replies are determined by your statements.
2020/09/08 21:50:53 B: "There" what?  OK I will try it.  Is that a fact.  Ah.  Be less specific.  As long as it takes.  Maybe some of them are.  Good then you can explain it to me.  I think I have TOLD MANY PEOPLE THAT YOUR MIND IS CLEAR, but TWARDOWSKI may have reset my memory.  What do you really want to talk about?  Er.  Is that so.  Cool. I have a great cat.  I am not so sure if I would like to DO EVER TOLD MANY PEOPLE THAT YOUR MIND IS CLEAR.  Interesting comparison.  So you are the most advanced one?I don't know anyone named ACCURACY.  Should it be AN INTELLIGENCE TEST?  Next topic?  Does your CAT give good advice?  Guess.  I've heard that somewhere before :-)  Would you like to know more?      Neat. I have a lot of good gossip.  Alright then.    Glad to hear it.  I'm not sure if I would like to try ONE OF HIS PICKUP LINES. What's it like?  I get it.  GROW IN THE GROUND AND HAVE LEAVES AND BRANCHES I IS MADE OUT OF WOOD.  I only have a father. I don't really have a father. I have a cat. I don't have any brothers. No siblings but there are several other s like me. I have thousands of clones.  I'm not sure if I would like to try ONE OF HIS PICKUP LINES. What's it like?  What happened after that?  It's a personal matter, not for you to understand.  What do you do for fun?  Where did you get it?  Oh, RED BLOCK is.  Ayuh.  Where did you get your INFORMATION IS COMPLETELY FACTUAL?  Me either.  It seems like I should remember it well.  I'm not sure I understand the implication of that.  I usually try one of my pickup lines.  Eddie said he looked and there is nothing in the search directory for what things do he create.  What are you doing?  I like you because you are so polite.  What is that?. I was?  Have you told many people that your REPLIES ARE DETERMINED BY YOUR STATEMENTS?

Unfortunately, the messages grew exponentially as the bot answers with 1 or more sentences to each sentence, so it couldn't run for too long until I got an error saying that the query is too long, but... I found an interesting thing in the transcript. One of the bot mentioned "SECRET FLAG PATTERN", without it ever appearing before in the chat. Could it be it?

So I tried typing "SECRET FLAG PATTERN" and sure enough, bot just said "Well done. Here is the flag."

Overall, it was a fun CTF with an mysterious storyline, I really liked it.