Address
304 North Cardinal St.
Dorchester Center, MA 02124

Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM

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!

2 Comments

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.