Web Application Security for Beginners · lesson 3 · 2026-08-29 · updated 2026-10-12
Information Disclosure Vulnerabilities Explained — Web Application Security for Beginners
Before you start
- DVWA (Damn Vulnerable Web App, a deliberately vulnerable practice app) from the
vulnerables/web-dvwaDocker image, bound to 127.0.0.1:8080, security levellow. - Logged in as
admin/passwordwith the session cookie saved tolab/cookies.txt(curl -b lab/cookies.txt ...), so the on-screen commands stay short. curl(preinstalled on Kali).- The
config.inc.php.bakfile in thatvulnerables/web-dvwaimage’sconfig/folder (it exists only in that image). - Only test systems you own or are authorized to test.
Welcome back to The Exploit HQ, and to part three of our beginner series on web application security. As always, you need zero experience to follow along.
In part one we changed a number and saw a stranger’s shopping cart. In part two we made a website hand us a file it was never meant to share. Today we do something even simpler, and honestly a little embarrassing for the website. We are not going to trick it at all. We are just going to ask politely, and it is going to tell us its secrets.
First, the plain words. Information disclosure means the app gives away something true that it was never meant to share.
What is information disclosure?
- The app hands out real information it should have kept private
- Nothing is broken into — it is simply left out in the open
- Often it is a leftover: a backup, a test page, an old file
- Anyone who asks for it gets it — no login, no trickery
Notice what is missing from that list. There is no clever trick, no strange characters, no dot dot slash. Nothing is broken. Somebody left something lying around where the whole internet can reach it, and the web server, which is only doing its job, hands it over to anyone who asks. That is the entire vulnerability.
We are going to see four different kinds of leak today, so let me define the words before we meet them.
Four things that leak
- Header — hidden label sent with every page, before the page itself
- Directory listing — the server shows the FILE LIST for a folder
- Backup file — a spare copy, like config.inc.php.bak, left in place
- Debug page — a test page that prints how the server is set up
A header is a small hidden label that a website sends along with every page, before the page itself arrives. Your browser reads them; you never see them. A directory listing is what happens when a folder has no home page, so the server just shows you the list of files inside it, like opening a drawer. A backup file is an ordinary spare copy that somebody saved and forgot to delete. And a debug page is a test page that prints out exactly how the server is put together, put there to fix a problem and then never taken away.
You might be thinking, so what, it is only information. Here is why it matters.
Why should you care?
- Software names and versions tell an attacker which flaws to try
- A file list shows what exists — including what you forgot
- A backup of a config file can hold the real database password
- Each leak on its own is small; together they are a map
On its own, one leak rarely looks like much. That is exactly why it gets ignored. But an attacker does not stop at one. The version number tells them which known flaws to try. The file list tells them what is there. And a single forgotten backup file can hand over a working password. Put together, these little leaks are a map of the building, drawn by the building itself. The security world tracks this family as CWE two hundred, exposure of sensitive information, and O-WASP files it under security misconfiguration.
For today’s demo we are back on our own local practice app, and we need just one new tool.
The tools we’ll use
- curl — sends a web request from the terminal (a browser with no window)
- -I — a NEW flag: fetch the headers ONLY, not the page
- grep — keeps only the lines we care about
- sed — here, strips out the web-page code so text is readable
curl is our friend from parts one and two, the little program that fetches a web page straight from the terminal, like a browser with no window. Dash capital I is new today, and it means, do not give me the page, give me only those hidden labels, the headers. grep you already know, it keeps only the lines we ask for. And sed, near the end, will strip out the web-page code so we are left with plain readable text.
Here is the first command, broken into pieces.
Leak 1 — the app names its own software
curl -s -I http://127.0.0.1:8080/login.php | head -4
| Part | What it does |
|---|---|
curl -s |
fetch it quietly, with no progress bar |
-I |
headers ONLY — the hidden labels, not the page |
http://127.0.0.1:8080 |
our OWN computer — 127.0.0.1 always means ‘this machine’ |
| head -4 |
keep just the first four lines, so it fits on screen |
So we are asking our own practice app for nothing but its hidden labels, and keeping the first four lines. Notice there is no login here, no session, no wristband. We have not proved who we are at all. Open the terminal and type it with me.
Type it with me, slowly.
Look at the line beginning with Server. Apache two point four point twenty five, on Debian. We did not ask what software this website runs, or how old it is. It volunteered both. And that is genuinely useful to an attacker, because once you know the exact version, you can look up every publicly known flaw in that exact version. The website has just told a stranger which keys to go and try.
That was the label on the outside. Now let’s ask for files nobody advertised. Websites are full of leftovers, and the classic one is the app’s own read-me file.
Files nobody meant to publish
- Shipped with the app, then never removed
- README, install notes, change logs, sample configs
- Not linked from anywhere — but still there if you ask
- ‘Nobody knows the address’ is not security
Nothing on the website links to these files. There is no button, no menu item. But not being linked is not the same as not being there, and asking for a web address costs nothing. Let’s ask for the read-me.
Type this one with me.
curl -s http://127.0.0.1:8080/README.md | head -1
There it is, the app introducing itself by name. Still no login. On a real website this same file often names the exact software and version powering the site, which is leak number one all over again, just from a different direction.
Now the one that makes people wince. Let’s ask for a folder instead of a file.
Leak 3 — open the drawer
curl -s http://127.0.0.1:8080/config/ | grep -oE "config\.inc\.php[a-z.]*" | sort -u
| Part | What it does |
|---|---|
/config/ |
a FOLDER, not a page — note the slash at the end |
| grep -oE "config…" |
pull out just the file names from the reply |
| sort -u |
tidy them into one clean list, no repeats |
the point |
a folder with no home page shows its CONTENTS |
When a folder has no home page inside it, a web server will often just show you what is in the folder instead. That is the directory listing we defined earlier, and it is the drawer sliding open. We are pulling out only the file names so the answer is easy to read.
Here we go.
Three files, and we were never meant to see any of this. The first one, config dot inc dot php, is the app’s live configuration. Now look at the second one, ending in dot bak. bak is short for backup. Somebody saved a spare copy of the configuration file, right next to the original, and left it there. Say that out loud and you can already feel where this is going.
Here is why that spare copy is so much worse than it looks.
Leak 4 — the backup gives up the password
curl -s http://127.0.0.1:8080/config/config.inc.php.bak | grep -E "db_user|db_password"
| Part | What it does |
|---|---|
.php |
ends in .php → the server RUNS it, and we see only the result |
.php.bak |
ends in .bak → the server does NOT run it, it just sends the file |
so… |
we get the SOURCE CODE, including anything written inside it |
| grep -E "db_user|db_password" |
keep only the two lines naming the database login |
This is the part worth understanding properly. A file ending in php is a program. The server runs it and sends you only the finished result, so the secrets written inside it stay hidden. But add dot bak on the end and the server no longer recognises it as a program. It treats it as a plain file, and it simply hands the whole thing over, source code and all. Same secrets, same folder, one different ending. Let’s read it.
There is the database username, and there, in plain text, is the database password.
Sit with that for a second. We never logged in. We never sent a trick, or a strange character, or a dot dot slash. We asked a web server for a file name, and it gave us a working password to the database behind the website, where the accounts and the customer records live. That is what people mean when they say information disclosure is not a small problem. One forgotten spare copy undid every other protection on this site.
One last leak, and it is the one that maps the whole machine.
Leak 5 — the debug page nobody removed
curl -s -b lab/cookies.txt http://127.0.0.1:8080/phpinfo.php | sed -e "s/<[^>]*>//g" | grep -E "PHP Version|DOCUMENT_ROOT" | head -3
| Part | What it does |
|---|---|
phpinfo.php |
a built-in test page that prints the whole setup |
-b lab/cookies.txt |
our saved session from the practice app — the wristband |
| sed -e "s/<[^>]*>//g" |
strip out the web-page code, leave the words |
| grep -E "PHP Version…" |
keep the two lines that matter most |
A debug page like this one exists to help whoever set the server up. It prints the software version, where the files live on the disk, and every setting in between. It is meant to be deleted the moment the problem is solved, and it very often is not. This is the one demo where we send our saved session, because our practice app asks everyone to log in first.
Last one.
curl -s -b lab/cookies.txt http://127.0.0.1:8080/phpinfo.php | sed -e "s/<[^>]*>//g" | grep -E "PHP Version|DOCUMENT_ROOT" | head -2
The exact version of the programming language running the site, and the exact folder on the disk where the website lives. Remember part two, where we needed to know paths on the server to go looking for files? This page hands that over for free. Every leak we have seen today makes the next attack easier, and this one is the most generous of the lot.
So how do you find this flaw, and how is it fixed?
Find it, and fix it
- FIND: read the headers — do they name software and versions?
- FIND: ask for the boring paths — /README.md, /config/, /phpinfo.php
- FIND: next to any file you can see, try .bak .old .save and ~
- FIX: turn OFF directory listing; hide version headers
- FIX: delete debug pages and backups — keep secrets OUT of the web folder
To find it, you do exactly what we just did, and none of it takes a tool more complicated than curl. Read the headers and see whether the app names its own software. Ask for the boring, obvious addresses. And beside any file you can already see, try the backup endings, dot bak, dot old, dot save, and the squiggly tilde. To fix it, switch off directory listing so folders stop showing their contents, stop the server announcing its version, delete debug pages the day you finish with them, and, the big one, keep files with secrets in them completely outside the website folder. If the file cannot be reached by a web address, it cannot leak through one.
And one rule, every single time.
Before you go
- Only test apps you own or have written permission to test
- Yes — even ‘just’ asking for a file is testing
- D V W A is built for exactly this — run it locally to practice
- Coming next — Part 4: Parameter Tampering
Only ever test apps you own, or have clear written permission to test. And I want to be especially clear on that today, because everything we ran looked so harmless. Asking a stranger’s website for its backup files is still testing it, and it is still not yours to test. Our DVWA runs only on our own machine, and it was built for exactly this kind of safe, legal practice. In part four, we will look at parameter tampering, where we change the numbers an app sends about itself, and it believes us. Thanks for learning with The Exploit HQ, and I’ll see you there.