CTF Regex for Flags and Victory (DerbyCon 2019)

We have been using some CTF regex recently, and I thought it was worth sharing.

CTF Regex - Introduction

During our first DerbyCon CTF, we ended up missing a few flags that could have gotten us the win.

While that stung, we wanted to make sure it didn't happen again. For this specific issue, we had our regex guru, RecViking, get to work on a solution.

In the end, he whipped together a one-liner for us to use, and I ended up finding at least one new flag with it during our DerbyCon 9 victory!

DerbyCon Flags

If you've never competed in a DerbyCon CTF, then the following is an example of what the flags look like.

NiceIDORExploitYo349

These flags are camel case, long, and have some numbers in the middle/at the end.

You can find the command that RecViking came up below to find these for us. Note that this will search the entire disk, but you can narrow it down to specific directories if you'd like.

egrep -r -o -e "[A-Z]([A-Z0-9]*[a-z][a-z0-9]*[A-Z]|[a-z0-9]*[A-Z][A-Z0-9]*[a-z])[A-Za-z0-9]*" / | sed -n '/.\{12\}/p' | sort | uniq

The grep command will look for camel case patterns that might resemble flags, and then the sed command just narrows down the results to anything over 12 characters. We ran into a lot of broken ASCII inside of binary files, and all the flags that we had saved were at least 14 characters.

As I'm not the regex expert, I recommend you check out the explanation on regex101 if you want to understand it further.

CTF Regex - Testing the Command

While I do not have all the flags from the DerbyCon 9 CTF, I did grab some from our Trello board.

FinalLap
RedDot
DoesNotMatter
PapersPlease
PapersPlease
DerpMail
Kc57LovesDotNetObfuscation
Kc57Kc57Kc57Kc57
StormbeatherintheUncannyX-Men170
TheRedirectMasta
PerlFTWLarryRules
IReadYourEmails7331
DESTROYallSOFtWare!!
Mutantsgotclawsinthe212
GeneNationandthe198
IceIceBabyIceCubeIceT993
OMGCanHazSomePointz2332
HerpDerp8234DerpHerp
ItIsIllegalToHackDis23444
DerpyAdm
fileserve
files
DerpyConIzDaB3stConferenceEVAR1337
NiceIDORExploitYo349
DerpyDB
HerpDerpyConAdmin
D3rpyC0n
Congr4tzYouG0t@Dm1n8888
TableNameForBigMoney777858
ColumnNameForTheWin939
IfYouGotThisYouAreAmazing999333
YouAreTheTrueSQLMaster77727
YouReadTheSourceCodeDerpDerp
ATicketToTheShow
WooYouAreAStaffMember
WooYouGotIn!
WellYouAreOnTheConsoleNowMyFriend
DoesAnyoneRememberPwndU
DerpyCon
HeyYouDeserveAFlagForYourWebShell
AhYouHaveUsedTheSrcLuke
OkNowYouRootedMyBoxDadGum
GoodYoureStillReadingHTMLComments
WebminOnTheBeach
ProcFlagProcFlagProc
R007LOGINSHELLZ
LOGINSHELLZ
DoesNotMatter
AmaraAquillafromBC44
Livingunderthe10110

I'm not certain which of these were found with our one-liner, but I know that at least one was.

While these flags were obviously in different file types, grep would be able to search my test file just fine.

doyler@mbp:~/Documents/grep$ sort -u test.txt | wc -l
      48

When I ran this command in my test directory, I managed to find 87.5% (42/48) of my saved flags!

doyler@mbp:~/Documents/grep$ egrep -r -o -e "[A-Z]([A-Z0-9]*[a-z][a-z0-9]*[A-Z]|[a-z0-9]*[A-Z][A-Z0-9]*[a-z])[A-Za-z0-9]*" ./ | sed -n '/.\{12\}/p' | sort | uniq
.//test.txt:ATicketToTheShow
.//test.txt:AhYouHaveUsedTheSrcLuke
.//test.txt:AmaraAquillafromBC44
.//test.txt:ColumnNameForTheWin939
.//test.txt:Congr4tzYouG0t
.//test.txt:D3rpyC0n
.//test.txt:DESTROYallSOFtWare
.//test.txt:DerpMail
.//test.txt:DerpyAdm
.//test.txt:DerpyCon
.//test.txt:DerpyConIzDaB3stConferenceEVAR1337
.//test.txt:DerpyDB
.//test.txt:DoesAnyoneRememberPwndU
.//test.txt:DoesNotMatter
.//test.txt:FinalLap
.//test.txt:GeneNationandthe198
.//test.txt:GoodYoureStillReadingHTMLComments
.//test.txt:HerpDerp8234DerpHerp
.//test.txt:HerpDerpyConAdmin
.//test.txt:HeyYouDeserveAFlagForYourWebShell
.//test.txt:IReadYourEmails7331
.//test.txt:IceIceBabyIceCubeIceT993
.//test.txt:IfYouGotThisYouAreAmazing999333
.//test.txt:ItIsIllegalToHackDis23444
.//test.txt:Kc57Kc57Kc57Kc57
.//test.txt:Kc57LovesDotNetObfuscation
.//test.txt:NiceIDORExploitYo349
.//test.txt:OMGCanHazSomePointz2332
.//test.txt:OkNowYouRootedMyBoxDadGum
.//test.txt:PapersPlease
.//test.txt:PerlFTWLarryRules
.//test.txt:ProcFlagProcFlagProc
.//test.txt:RedDot
.//test.txt:StormbeatherintheUncannyX
.//test.txt:TableNameForBigMoney777858
.//test.txt:TheRedirectMasta
.//test.txt:WebminOnTheBeach
.//test.txt:WellYouAreOnTheConsoleNowMyFriend
.//test.txt:WooYouAreAStaffMember
.//test.txt:WooYouGotIn
.//test.txt:YouAreTheTrueSQLMaster77727
.//test.txt:YouReadTheSourceCodeDerpDerp
doyler@mbp:~/Documents/grep$ egrep -r -o -e "[A-Z]([A-Z0-9]*[a-z][a-z0-9]*[A-Z]|[a-z0-9]*[A-Z][A-Z0-9]*[a-z])[A-Za-z0-9]*" ./ | sed -n '/.\{12\}/p' | sort | uniq | wc -l
      42

When I inverted the matches, I was able to see the six flags that my command did not not return.

doyler@mbp:~/Documents/grep$ egrep -r -o -v "[A-Z]([A-Z0-9]*[a-z][a-z0-9]*[A-Z]|[a-z0-9]*[A-Z][A-Z0-9]*[a-z])[A-Za-z0-9]*" ./ | sed -n '/.\{12\}/p' | sort | uniq | wc -l
       6
doyler@mbp:~/Documents/grep$ egrep -r -o -v "[A-Z]([A-Z0-9]*[a-z][a-z0-9]*[A-Z]|[a-z0-9]*[A-Z][A-Z0-9]*[a-z])[A-Za-z0-9]*" ./ | sed -n '/.\{12\}/p' | sort | uniq
.//test.txt:LOGINSHELLZ
.//test.txt:Livingunderthe10110
.//test.txt:Mutantsgotclawsinthe212
.//test.txt:R007LOGINSHELLZ
.//test.txt:files
.//test.txt:fileserve

As you can see, these flags were either not long enough, or not quite camel case.

Other CTFs

This strategy is even more useful in CTFs with a standard flag format.

For example, here is an example of me running this command during a CTF that RecViking was setting up.

ctfuser@ip-172-26-10-254:~$ egrep -r -o -e "flag{.*" / 2>/dev/null | sed -n '/.\{12\}/p' | sort | uniq
/home/ctfuser/.bash_history:flag{FLAG GOES HERE}
/home/ctfuser/.bashrc:flag{FLAG GOES HERE}
/home/ctfuser2/flag.txt:flag{FLAG GOES HERE}
/usr/bin/find:flag{FLAG GOES HERE}
/usr/bin/find:flag{FLAG GOES HERE}"
/usr/bin/nmap:flag{FLAG GOES HERE}
/usr/bin/nmap:flag{FLAG GOES HERE}"
/var/skel/.bash_history:flag{FLAG GOES HERE}
/var/skel/.bashrc:flag{FLAG GOES HERE}
/var/www/html/admin/index.html:flag{FLAG GOES HERE}
/var/www/html/index.html:flag{FLAG GOES HERE}
/var/www/html/robots.txt:flag{FLAG GOES HERE}: /
Binary file /proc/1361/cmdline matches
Binary file /proc/1361/task/1361/cmdline matches
Binary file /var/cache/snapd/commands.db matches

While this will not work in most Jeopardy style CTFs, it is great to run for something that is scenario-based, like our EverSec CTF.

CTF Regex - Conclusion

This was a command that we got from RecViking, but I wanted to share it now that DerbyCon is over.

While less relevant to my future CTFs, I also thought about trying to use something like YARA rules to do something similar.

If you have any other examples of indirectly searching for flags, then I'd love to hear them!

doyler on Githubdoyler on Twitter
doyler
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he's done it all. To show for it, he has obtained an OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!

He currently serves as a Senior Staff Adversarial Engineer for Avalara, and his previous position was a Principal Penetration Testing Consultant for Secureworks.

When he's not figuring out what cert to get next or side project to work on, he enjoys playing video games, traveling, and watching sports.

As an Amazon Associate I earn from qualifying purchases.

Common passed on this blog, I made it to a jam.

2 Comments

Filed under Security Not Included

2 Responses to CTF Regex for Flags and Victory (DerbyCon 2019)

  1. Cyril

    Great article! I use this online regex tester to check my regular expressions: https://extendsclass.com/regex-tester.html

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.