Step 98. Bandit 11~15 — Encoding and Network Connections

Step 98. Bandit 11~15 — Encoding and Network Connections

Level 2 — Introduction to Security and Attack Skill Basics | Difficulty ★★☆☆☆ | Estimated time: 3 hours

Prerequisites: you’ve finished the solving cycle and find techniques from Steps 96~97, and the Bandit 10→11 password. You know what a port is.

  • What you need: an SSH connection environment, your password record, and a local Linux/WSL setup (with tr, nc, openssl).
  • ⚠️ All exercises in this chapter are for your own lab and legal platforms only. Applying them to unauthorized systems is a crime.
  • About the legal practice ground: OverTheWire Bandit is a learning platform where attack practice is officially permitted. The only targets you connect to with nc and openssl s_client are the Bandit server and services you launch yourself on your own computer.

From the middle of Bandit onward, the character of the problems changes. If the early levels were "finding files," now it’s transformation and conversation: untangling twisted strings (encoding) and speaking directly to network ports (sockets). The reason this stretch matters is simple — the tools used here are the bare-hand weapons of real fieldwork. nc is called "the hacker’s Swiss Army knife." The simplicity of connecting to any port and exchanging text is the starting point of all manual web vulnerability testing.


1. Learning Objectives

By the end of this chapter, you will be able to:

  • Perform character substitutions like ROT13 with tr and explain the principle
  • Peel a multiply wrapped file to the end with a "identify → decompress" loop
  • Connect to arbitrary ports with nc and exchange text
  • Talk to a TLS port with openssl s_client and tell it apart from a plaintext port
  • Connect with an SSH private key and explain why key files need permission 600

2. Background Knowledge — Today’s Tools and Concepts

Today’s Tools at a Glance

Category Details
Language/environment Linux shell (Bandit server + local WSL)
Today’s commands tr, xxd -r, gzip -d, bzip2 -d, tar -xf, nc, openssl s_client, ssh -i, chmod 600
Concepts needed Substitution ciphers (ROT13), magic numbers and compression formats, sockets and ports, the TLS handshake, private-key authentication
Today’s artifact Bandit 11→16 password chain + 3 tool cards (tr, nc, s_client)

2-1. ROT13 — A Substitution That Shifts the Alphabet by 13

ROT13 is a substitution cipher that shifts each letter by 13 positions: A→N, B→O, …, N→A. Since the alphabet has 26 letters, applying it twice returns the original — transforming and reversing are the same operation.

It’s not real encryption: the rule is public, so anyone can reverse it without a key. But it’s the entrance to the "substitution" family, and Linux’s tr performs this transformation in one line. Like Base64 (Step 97), this is another section confirming that "scrambled" doesn’t mean "safe."

2-2. nc — The cat of Networks

nc (netcat) is "the cat of networks." Just as cat reads a file and spills it to the screen, nc connects to a port and sends and receives.

nc address port      # connect to that port and start a conversation
nc -l -p port        # wait on that port (I become the server)

All of Bandit’s "send the current password to port N on localhost" problems are solved with this tool. This structure — "I speak to a service directly" — later becomes the basic posture of manual testing, where you craft web requests by hand.

2-3. openssl s_client — Speaking Through an Encrypted Channel

Some services only accept conversations over TLS, not plaintext. Connecting to such a port with nc won’t produce a working conversation. That’s when you use:

openssl s_client -connect address:port

Think of it as "nc that lays down an encrypted channel for you." It handles the TLS handshake (cipher negotiation and key exchange) for you, and everything after that is delivered exactly as you type it. Encryption guards the channel — it doesn’t change the contents inside.

2-4. SSH Private Keys — An ID Card Instead of a Password

So far we’ve connected with passwords, but SSH can also connect using a private key file. If a password is "something you know," a key file is "something you have." You specify the key with the -i option.

ssh -i keyfile user@address -p port

However, if the key file’s permissions are open (readable by others), SSH itself refuses to use it — it treats the key as "possibly already leaked." The fix is chmod 600: "owner read/write only."


3. Follow Along

3-1. Level 11 → 12 — Solving ROT13 with tr

This data.txt is a string with the alphabet shifted by 13 positions.

Input (on the server, Screen example)

cat data.txt | tr 'A-Za-z' 'N-ZA-Mn-za-m'

Local reproduction (measured 2026-09-09, WSL):

echo 'Gur cnffjbeq vf jbxrrq' | tr 'A-Za-z' 'N-ZA-Mn-za-m'
The password is wokeed

How to read it: tr 'original letters' 'replacement letters' substitutes characters one-to-one. The array chaining uppercase A~Z onto N~ZA~M is the formula for a 13-position shift. Run the same command once more and it scrambles again — verify for yourself the property that twice returns the original.

Why: tr isn’t a ROT13-only tool; it’s a general-purpose substitution tool. For example, echo 'hello world' | tr 'a-z' 'A-Z' produces HELLO WORLD (measured 2026-09-09). Remember it as a staple of text processing.

3-2. Level 12 → 13 — Peeling Layer after Layer

This file is a hex dump; reverse it and you get a compressed file; decompress that and you get yet another compressed file — an onion structure.

Repeating recipe — one layer at a time with the tool matching file‘s verdict (on the server, Screen example):

mkdir /tmp/mywork123 && cd /tmp/mywork123
cp ~/data.txt .
xxd -r data.txt > out1       # hex dump → binary
file out1                    # what is this layer?
# if gzip:  mv out1 out2.gz && gzip -d out2.gz
# if bzip2: mv out2 out3.bz && bzip2 -d out3.bz
# if tar:   mv out3 out4.tar && tar -xf out4.tar

We reproduced this whole loop on our own computer — a file wrapped in three layers: bzip2 → gzip → tar (measured 2026-09-09, WSL):

echo 'The final password is onion_core!' > plain.txt
tar -cf stage1.tar plain.txt
gzip -c stage1.tar > stage2.gz
bzip2 -c stage2.gz > stage3.bz
file stage3.bz

Output (measured 2026-09-09, peeling one layer at a time):

stage3.bz: bzip2 compressed data, block size = 900k
(after bzip2 -d)  step: gzip compressed data, was "stage1.tar", ...
(after gzip -d)   step: POSIX tar archive (GNU)
(after tar -xf)   plain.txt appears → cat it: "The final password is onion_core!"

How to read it: at every step, file tells you "what this layer is." Identify → peel with the matching tool → identify again — this loop is the basic shape of file forensics. Tools like gzip -d require the extension (.gz), so renaming first with mv is the key move.

3-3. Level 13 → 14 — Connecting with a Private Key

This time the home folder holds a key file called sshkey.private instead of a password.

Input (on the server, Screen example)

chmod 600 sshkey.private
ssh -i sshkey.private bandit14@localhost -p 2220

If the permissions are open, SSH refuses like this (Screen example):

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0664 for 'sshkey.private' are too open.

How to read it: a key is an ID card. The system doesn’t trust an ID card that others could have copied. Narrow it to "owner only" with chmod 600 and the connection succeeds — without typing a password even once.

Why: production servers often enforce key-based login instead of passwords, and in incident response, a leaked key file is a disaster on par with a leaked password.

3-4. Level 14 → 15 — Talking to a Service with nc

Goal: "send the current password to port 30000 on localhost."

Input (on the server, Screen example)

cat /etc/bandit_pass/bandit14    # readable while logged in as bandit14
nc localhost 30000

Once connected, it quietly waits for input. Paste the password and hit Enter — Correct! comes back along with the next password.

We reproduced this entire conversation on our own computer: one listening nc (server), one connecting nc (measured 2026-09-09, WSL):

# Terminal 1 (the listening side)
echo 'Correct! next_password_is_abc123' | nc -l -p 34567
# Terminal 2 (the connecting side)
echo 'current_password_xyz' | nc 127.0.0.1 34567

Output (measured 2026-09-09, Terminal 2’s screen):

current_password_xyz
Correct! next_password_is_abc123

How to read it: with no browser and no dedicated client, a human and a service talked directly in raw text over a socket. This is the beginning of the experience of "speaking a protocol yourself."

3-5. Level 15 → 16 — Talking to a TLS Port

Same method, but this port (30001) requires SSL/TLS encryption.

Input (on the server, Screen example)

openssl s_client -connect localhost:30001

After the handshake logs scroll by and it goes quiet, type the password. We measured this process by standing up a local TLS server (measured 2026-09-09, WSL — we created a self-signed certificate and opened a test server with openssl s_server):

Output (measured 2026-09-09, part of the handshake log):

CONNECTED(00000003)
---
Certificate chain
 0 s:CN = localhost
   i:CN = localhost
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIDCTCCAfGgAwIBAgIUe/J10N2ZHt4zwerNUs5cAdwQ3gwwDQYJKoZIhvcNAQEL
...

Once the channel is laid, strings you send are delivered as-is. In our measurement, sending my_password_123 made the server (echo mode) flip the received content back, showing the connection had been established.

How to read it: the Certificate and Cipher information at the top of the output is the trace of the TLS handshake. The conversation after the channel is laid is plaintext, exactly like nc — encryption guards the channel; it doesn’t change the contents.

3-6. Talking to a Web Server with nc — Typing HTTP by Hand

nc’s true worth shows on the web. Launch a simple web server on your own computer and type a request by hand.

Input (Terminal 1)

cd /tmp && python3 -m http.server 8000

Input (Terminal 2 — type the GET line and press Enter twice)

nc 127.0.0.1 8000
GET / HTTP/1.0

How to read it: you just did by hand what a browser does. One line GET / HTTP/1.0 plus a blank line is the minimal form of an HTTP request. Send GET /nonexistent HTTP/1.0 and you’ll see a 404 response with your own eyes — the moment you feel that status codes are not textbook entries but replies in a conversation.

Why: web vulnerability testing ultimately repeats the question "if I twist this request strangely, how does the server react?" The three lines you typed by hand today are the prototype of all those experiments.


4. Missions & Exercises

Mission — The Bandit 11→16 Chain and Tool Cards

  1. Complete the password chain through bandit15 and record each level in write-up format
  2. Record Level 12’s onion peeling step by step — which layers (formats) there were and how many
  3. Write 3 tool cards in your wiki — tr, nc, openssl s_client. For each: "what it does / a representative example / when to reach for it"
  4. Reproduce the two-terminal nc conversation locally and keep a screenshot or log

Exercises

Exercise 1. Explain, connecting it to the number of letters in the alphabet, why applying ROT13 twice returns the original string.

Exercise 2. Explain why gzip -d out1 throws an "unknown suffix" error and the procedure to fix it.

Exercise 3. What happens when you connect to a TLS-only port with nc, and why?

Exercise 4. Explain, using the "ID card" analogy, why SSH rejects a private key with permission 644.


5. Model Answers & Completion Criteria

Mission Model Answer

The skeleton of the chain (on-server commands are a Screen example):

cat data.txt | tr 'A-Za-z' 'N-ZA-Mn-za-m'              # L11→12
# L12→13: repeat the xxd -r → file → (gzip|bzip2|tar) decompress loop
chmod 600 sshkey.private && ssh -i sshkey.private bandit14@localhost -p 2220   # L13→14
cat /etc/bandit_pass/bandit14 && nc localhost 30000    # L14→15
openssl s_client -connect localhost:30001              # L15→16

How to verify: ① does each of the 3 tool cards have "an example I ran myself" attached? ② does the onion-peeling record note the layer order (the order in which gzip/bzip2/tar appeared)? ③ in the local nc conversation, are both terminals’ sends and receives cross-confirmed?

Exercise Answers

Answer 1. The alphabet has 26 letters, and 13 is exactly half. Shifting 13 twice makes 26 — one full rotation back to the start. That’s why transforming and reversing are the same command (the reason the tr array in the section 3-1 measurement is symmetric).

Answer 2. gzip -d identifies the format by the file’s suffix (.gz), and the name lacks that marker. Fix it by adding the extension with mv out1 out1.gz before decompressing. The habit of checking with file at every step prevents this accident.

Answer 3. The server expects a TLS handshake (cipher negotiation messages), but nc just pushes plain text, so no conversation is established. You get strange bytes or silence followed by a dropped connection. The sense to distinguish "is this port plaintext or TLS?" is a basic skill of real-world reconnaissance.

Answer 4. Permission 644 means "other users can read it too." An ID card others could copy may already be forged, so the system refuses to use it on its own. Trust is restored only after narrowing it to chmod 600 (owner only).

Completion Criteria Checklist

  • [ ] I can decode ROT13 with tr and explain the principle of substitution
  • [ ] I can peel a multiply compressed file to the end with a file + decompression-tool loop
  • [ ] I can connect to a port with nc and exchange text
  • [ ] I can talk to a TLS port with openssl s_client
  • [ ] I can test whether a port is plaintext or TLS using the two tools
  • [ ] I can explain SSH private-key login and the reason for permission 600
  • [ ] Mission: I completed the chain and the 3 tool cards

6. Common Pitfalls & Fixes

Wall 1. ssh -i rejects the key

Symptom (Screen example):

WARNING: UNPROTECTED PRIVATE KEY FILE!
Permissions 0664 for 'sshkey.private' are too open.

Cause: others can read the key file. SSH doesn’t trust a key that may have leaked.
Fix: chmod 600 keyfile. If permission changes are blocked on the server, copy the key to your own /tmp and fix it there.

Wall 2. Decompression fails with "unknown suffix"

Symptom (measurement-style message):

gzip: out1: unknown suffix -- ignored

Cause: gzip -d requires the .gz extension.
Fix: mv out1 out1.gz && gzip -d out1.gz. And never skip the file check at each step — you’ll lose track of which layer got tangled.

Wall 3. I connected with nc but hear nothing

Symptom: no output at all after connecting.
Cause: that’s often normal — some services don’t speak first, so you have to type first.
Fix: enter the password and hit Enter. If silence persists, check the port number and "did I use the current level’s password?"

Wall 4. openssl s_client floods the screen

Symptom: certificates and cipher lists fill the screen.
Cause: that’s normal — it’s showing you the entire handshake process (see the measured output in section 3-5).
Fix: wait until the output stops and it goes quiet, then type. If you want less output, add the -quiet option.

Wall 5. The listening nc and the connecting nc don’t know each other

Symptom: nothing happens on either terminal.
Cause: the port numbers differ, or you launched the listening side (nc -l) after the connecting side.
Fix: the order is ① start waiting with nc -l -p port → ② connect from another terminal → ③ same port number. Since it’s localhost there’s no firewall variable — just get these three right (exactly the measured procedure in section 3-4).


7. Summary

Today’s Concepts

Concept One-line explanation
ROT13 a 13-position alphabet substitution — twice returns the original
Substitution cipher a transformation swapping characters one-to-one — reversible without a key means it’s not encryption
Socket conversation the minimal unit of communication: speaking directly to a port
TLS handshake cipher negotiation and key exchange — guards the channel, leaves contents alone
Private-key authentication login proven by "something you have" — permission 600 is the condition of trust

Today’s Commands

Command What it does
tr 'A-Za-z' 'N-ZA-Mn-za-m' ROT13 substitute/restore
xxd -r file > output hex dump to binary
gzip -d / bzip2 -d / tar -xf decompress one layer at a time
nc address port connect to a port and talk
nc -l -p port become a server waiting on a port
openssl s_client -connect address:port talk over a TLS channel
ssh -i keyfile user@address connect with a private key
chmod 600 file owner read/write only

An Instinct More Important Than Commands

Today’s three tools tie together into one question — "when data’s appearance has changed, how do I talk to the original?" Substitution calls for tr, wrapping calls for decompression tools, an encrypted channel calls for s_client. Not fearing appearances is this section’s harvest. And a sentence to remember: "scrambled" is not "safe." Anything with a command that reverses it is an encoding, and an encoding is not protection. From files to networks, from reading to conversation — starting today, your hands touch services directly.


Once every box is checked, Step 98 is complete. Click the checkbox in the sidebar to save your progress.