Authentication Deep Dive — Proving You Are Who You Claim to Be
Thilan Dissanayaka Identity & Access Management May 16, 2020

Authentication Deep Dive — Proving You Are Who You Claim to Be

You type your username and password. You hit “Login.” A spinner appears for a second, and you’re in.

Simple, right? But what actually happened in that one second? How did the server verify your password without storing it in plain text? What got sent back to your browser to keep you logged in? And why does your bank ask you for a 6-digit code on top of your password?

Authentication is the first gate in any secure system. Before we decide what you can access or what role you have — we need to answer one fundamental question: Are you really who you claim to be?

In this post, we’re going deep. We’ll trace the entire authentication journey — from how passwords are stored, to how sessions work, to why the future is passwordless. Lets get into it.

The Three Factors of Authentication

Every authentication method falls into one (or more) of three categories. These are called authentication factors:

Factor What It Means Examples
Something you know A secret in your head Password, PIN, security question
Something you have A physical device you possess Phone (OTP), hardware key (YubiKey), smart card
Something you are A biometric trait unique to you Fingerprint, face, iris, voice

Using one factor = single-factor authentication. Using two different factors = two-factor authentication (2FA). Using two or more = multi-factor authentication (MFA).

The key word is different factors. A password + a security question is NOT 2FA — both are “something you know.” A password + an OTP from your phone IS 2FA — one is “something you know,” the other is “something you have.”

This distinction matters more than people realize. Lets explore each one.

Passwords — The Oldest Trick in the Book

Passwords are the most common authentication mechanism on the planet. And also the most broken. But before we talk about why they’re broken, lets understand how they’re supposed to work.

The Naive Approach (Don’t Do This)

The simplest way to verify a password: store it in a database and compare.

Users Table:
┌──────────┬──────────────┐
│ username │ password     │
├──────────┼──────────────┤
│ thilan   │ MyP@ss123    │
│ alice    │ hunter2      │
│ bob      │ qwerty123    │
└──────────┴──────────────┘

User logs in → server fetches the password from the database → compares it with what the user typed → match? You’re in.

Sounds straightforward. But here’s the problem — if anyone gets access to this database (SQL injection, insider threat, misconfigured backup, leaked dump), they now have every user’s password in plain text. And since people reuse passwords across sites, that one breach can cascade into compromised email accounts, bank accounts, and everything else.

This is exactly what happened in the RockYou breach in 2009 — 32 million passwords stored in plain text. Not great.

So how do we store passwords without actually storing them? Hashing.

Hashing — One-Way Transformation

A hash function takes an input of any length and produces a fixed-length output (the hash/digest). The critical property: it’s a one-way function. You can go from password to hash, but you can’t go from hash back to password.

$ echo -n "MyP@ss123" | sha256sum
5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

Now instead of storing the password, we store the hash:

Users Table:
┌──────────┬──────────────────────────────────────────────────────────────────┐
│ username │ password_hash                                                    │
├──────────┼──────────────────────────────────────────────────────────────────┤
│ thilan   │ 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8│
│ alice    │ f52fbd32b2b3b86ff88ef6c490628285f482af15ddcb29541f94bcf526a3f6c7│
│ bob      │ ab5db4f1e4b8b2088a5fef1fcf67e4bfe0c7803774d44e41ccb7e2e3b0d5038b│
└──────────┴──────────────────────────────────────────────────────────────────┘

When the user logs in:

  1. User sends: username=thilan, password=MyP@ss123
  2. Server hashes the input: SHA256("MyP@ss123")5e884898da...
  3. Server compares with stored hash
  4. Match? You’re in. No match? Access denied.

The server never stores or even sees the actual password after the initial registration. Even if the database leaks, attackers only get hashes — not passwords.

But wait. Is hashing alone enough? Not quite.

The Problem with Plain Hashing — Rainbow Tables

Here’s the thing. SHA256("password123") always produces the same hash. Always. No matter who hashes it, no matter when. That means an attacker can precompute a massive table of common passwords and their hashes:

Rainbow Table:
password123  → ef92b778bafe771e89245b89ecbc08a44a4e166c06659911881f383d4473e94f
qwerty       → 65e84be33532fb784c48129675f9eff3a682b27168c0ea744b2cf58ee02337c5
letmein      → 1c8bfe8f801d79745c4631d09fff36c82aa37fc4cce4fc946683d7b336b63032
hunter2      → f52fbd32b2b3b86ff88ef6c490628285f482af15ddcb29541f94bcf526a3f6c7
... millions more ...

Now the attacker doesn’t need to “crack” anything. They just look up each hash in the table. If alice’s hash is f52fbd32b2b3..., one lookup reveals her password is hunter2. Done in milliseconds.

This is called a rainbow table attack. And it’s devastating against plain hashes.

Salting — Making Every Hash Unique

The fix? Salting. A salt is a random string that’s generated for each user and prepended (or appended) to the password before hashing.

password = "hunter2"
salt     = "x7Kp9mQ2"  (random, unique per user)

hash = SHA256("x7Kp9mQ2" + "hunter2")
     = a1c4e29f... (completely different from SHA256("hunter2") alone)

Now the database stores both the salt and the hash:

Users Table:
┌──────────┬──────────┬──────────────────────────────────────────────┐
│ username │ salt     │ password_hash                                │
├──────────┼──────────┼──────────────────────────────────────────────┤
│ alice    │ x7Kp9mQ2 │ a1c4e29f8b...                               │
│ bob      │ mN3pR8vK │ 7d2f9c1a5e...                               │
└──────────┴──────────┴──────────────────────────────────────────────┘

Even if alice and bob have the same password, their hashes are completely different because the salts are different. Rainbow tables become useless — the attacker would need a separate rainbow table for every possible salt, which is computationally infeasible.

The salt doesn’t need to be secret. It’s stored right next to the hash. Its only job is to ensure that identical passwords produce different hashes.

Proper Password Hashing — bcrypt, scrypt, Argon2

Here’s something a lot of developers get wrong. SHA256 is not a password hashing function. It’s a general-purpose hash function designed to be fast. And fast is exactly what you don’t want for password hashing — because fast means an attacker can try billions of guesses per second.

Proper password hashing algorithms are designed to be intentionally slow:

Algorithm Year Key Feature
bcrypt 1999 Configurable cost factor (work factor). Industry standard
scrypt 2009 Memory-hard — requires lots of RAM, not just CPU. Resists GPU attacks
Argon2 2015 Winner of the Password Hashing Competition. Memory-hard + configurable parallelism

Lets see bcrypt in action:

import bcrypt

# Registration — hash the password
password = b"MyP@ss123"
salt = bcrypt.gensalt(rounds=12)  # Cost factor = 12
hashed = bcrypt.hashpw(password, salt)

print(hashed)
# $2b$12$LJ3m4yPFSZEGOZEuWJ.e4OGz0Kv8Hwf0E9RnJeII.AkJGHnfbfyG

# Login — verify the password
entered_password = b"MyP@ss123"
if bcrypt.checkpw(entered_password, hashed):
    print("Access granted")
else:
    print("Access denied")

Look at that hash output: $2b$12$LJ3m4y.... It contains everything — the algorithm identifier (2b = bcrypt), the cost factor (12), the salt, and the hash. All in one string. No separate salt column needed.

The cost factor 12 means bcrypt will run 2^12 = 4096 iterations internally. On modern hardware, this takes about 250ms per hash. That’s nothing for a legitimate login — but for an attacker trying billions of passwords, it’s crippling.

SHA256:  ~10,000,000,000 hashes/sec on a GPU
bcrypt:  ~25,000 hashes/sec on a GPU (with cost factor 12)

Cracking time for a 8-char password:
SHA256:  seconds to minutes
bcrypt:  months to years

That’s the difference. Always use bcrypt, scrypt, or Argon2 for password storage. Never SHA256, MD5, or any general-purpose hash.

Password Attacks — What Attackers Do

Now that you know how passwords are stored, lets see how attackers try to crack them:

Brute Force — Try every possible combination. Works for short passwords, impractical for long ones.

a, b, c, ..., aa, ab, ac, ..., aaa, aab, ...

Dictionary Attack — Try words from a wordlist (common passwords, leaked databases).

$ head -5 /usr/share/wordlists/rockyou.txt
123456
12345
123456789
password
iloveyou

Rainbow Table Attack — Precomputed hash lookups. Defeated by salting.

Credential Stuffing — Take leaked username/password pairs from one breach and try them on other sites. Works because people reuse passwords. This isn’t really “cracking” — it’s exploiting human behavior.

Phishing — Don’t crack the password at all. Just trick the user into typing it on a fake login page. Still the most effective attack vector by far.

Sessions — Staying Logged In

Okay, so the user authenticated successfully. Great. But HTTP is stateless — every request is independent. The server doesn’t inherently remember that you logged in 2 seconds ago. So how do you stay logged in while browsing a site?

Sessions.

How Sessions Work

  1. User authenticates (username + password)
  2. Server creates a session — a record on the server with a unique ID
  3. Server sends the session ID back to the browser as a cookie
  4. Browser sends the cookie with every subsequent request
  5. Server looks up the session ID → finds the user → processes the request
Login:
Browser → Server:  POST /login  { username: "thilan", password: "MyP@ss123" }
Server:            Verifies password ✓
                   Creates session: { id: "abc123", user: "thilan", created: "..." }
Server → Browser:  Set-Cookie: session_id=abc123; HttpOnly; Secure

Subsequent requests:
Browser → Server:  GET /dashboard  Cookie: session_id=abc123
Server:            Looks up session "abc123" → found → user is "thilan"
Server → Browser:  200 OK (dashboard content)

The session data lives on the server. The cookie only contains the session ID — a random, opaque string. The browser knows nothing about the user’s roles, permissions, or any other data. It just presents its cookie like a movie ticket stub.

Session Security — What Can Go Wrong?

Sessions are a prime target for attackers. Here are the main threats:

Session Hijacking — If an attacker steals your session cookie, they can impersonate you. This is why cookies must have the HttpOnly flag (prevents JavaScript from reading them) and Secure flag (only sent over HTTPS).

Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=Strict; Path=/

Session Fixation — The attacker sets a known session ID in the victim’s browser before they log in. When the victim authenticates, the attacker already knows the session ID. Fix: always regenerate the session ID after successful authentication.

CSRF (Cross-Site Request Forgery) — An attacker tricks the victim’s browser into sending a request to a site where they’re logged in. The SameSite cookie attribute and CSRF tokens mitigate this. I’ve written about this in detail in the CSRF article.

Sessions vs Tokens — Server-Side vs Client-Side

Sessions are server-side — the server stores the state. This means the server needs to look up every session on every request. For a single server, that’s fine. But for a distributed system with multiple servers behind a load balancer — which server has the session?

Solutions:

  • Sticky sessions — Route the user to the same server every time. Fragile.
  • Shared session store — Use Redis or a database. Adds latency and a single point of failure.
  • Tokens (JWT) — Move the state to the client. No server-side storage needed.

This is where tokens come in. We’ll cover JWTs in detail in the next article in this series, but lets understand the concept here.

Token-Based Authentication

Instead of storing session data on the server, what if we encoded the user’s identity and permissions into the token itself and sent it to the client?

That’s the idea behind token-based authentication. The most common format is the JSON Web Token (JWT).

How It Works

  1. User authenticates (username + password)
  2. Server creates a JWT containing user info (claims), signs it with a secret key
  3. Server sends the JWT to the client
  4. Client stores it (usually in memory or localStorage) and sends it in the Authorization header with every request
  5. Server verifies the signature — if valid, trusts the claims inside the token
Login:
Browser → Server:  POST /login  { username: "thilan", password: "MyP@ss123" }
Server:            Verifies password ✓
                   Creates JWT: { sub: "thilan", role: "admin", exp: 1234567890 }
                   Signs it with secret key
Server → Browser:  { "token": "eyJhbGciOiJIUzI1NiIs..." }

Subsequent requests:
Browser → Server:  GET /dashboard
                   Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Server:            Verifies JWT signature → valid → user is "thilan", role is "admin"
Server → Browser:  200 OK

The critical difference — no server-side session storage. The server doesn’t need to look anything up. It just validates the JWT signature and reads the claims. This makes token-based auth ideal for distributed systems, microservices, and APIs.

A Quick Look Inside a JWT

A JWT has three parts separated by dots: header.payload.signature

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiJ0aGlsYW4iLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE3MTYyMzkwMjJ9.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Decode the payload (it’s just base64):

$ echo "eyJzdWIiOiJ0aGlsYW4iLCJyb2xlIjoiYWRtaW4iLCJpYXQiOjE3MTYyMzkwMjJ9" | base64 -d
{"sub":"thilan","role":"admin","iat":1716239022}

The token is signed, not encrypted. Anyone can read the payload — but they can’t modify it without invalidating the signature. We’ll go much deeper into JWT structure, signing algorithms, and common attacks in the dedicated JWT article.

Sessions vs Tokens — Quick Comparison

Aspect Sessions Tokens (JWT)
State Server-side Client-side
Storage Server (memory/Redis/DB) Client (memory/localStorage)
Scalability Needs shared store Stateless — scales easily
Revocation Easy — delete the session Hard — token is valid until it expires
Size Small cookie (~32 bytes) Larger (~500+ bytes with claims)
Best for Traditional web apps APIs, SPAs, microservices

Multi-Factor Authentication (MFA)

Passwords alone are not enough. They get phished, leaked, guessed, and reused. MFA adds extra layers of verification by requiring two or more different factors.

TOTP — Time-Based One-Time Passwords

When you scan a QR code with Google Authenticator or Authy, you’re setting up TOTP (RFC 6238). Here’s how it works:

  1. Server generates a shared secret (a random key, typically 20 bytes)
  2. The QR code encodes this secret so your authenticator app can store it
  3. Every 30 seconds, both the server and your app independently compute a 6-digit code using: TOTP = HMAC-SHA1(secret, floor(current_time / 30))
  4. Since both sides have the same secret and the same clock, they generate the same code
Shared secret: JBSWY3DPEHPK3PXP (base32 encoded)
Current time:  1716239022
Time step:     floor(1716239022 / 30) = 57207967

HMAC-SHA1(secret, 57207967) → ... → truncate → 483921

User enters: 483921
Server computes: 483921
Match! ✓

The beauty of TOTP — it works completely offline. Your authenticator app doesn’t need an internet connection. It just needs the secret and a reasonably accurate clock.

Weakness: TOTP is still vulnerable to real-time phishing. If an attacker sets up a fake login page that proxies to the real server, they can capture both your password AND the TOTP code and use them immediately. This is called an adversary-in-the-middle (AitM) attack.

SMS OTP — The Weakest Second Factor

You’ve probably received a text message with a 6-digit code during login. This is SMS OTP, and it’s the weakest form of MFA.

Why? Because SMS was never designed for security:

  • SIM swapping — An attacker convinces your carrier to transfer your phone number to their SIM. Now they receive your OTPs.
  • SS7 attacks — The SS7 signaling protocol (used by telecom networks) has known vulnerabilities that allow interception of SMS messages.
  • Phishing — Same AitM attack as TOTP. Attacker proxies the login page, captures the SMS code in real time.

NIST (the US National Institute of Standards and Technology) has actually deprecated SMS as an authentication factor in their guidelines. It’s better than nothing, but if you have a choice — use TOTP or a hardware key instead.

Push Notifications

Apps like Microsoft Authenticator and Duo send a push notification to your phone. You tap “Approve” and you’re in.

This is more user-friendly than typing a 6-digit code, and slightly more secure — the notification shows context (which app is requesting, from where). But it’s vulnerable to MFA fatigue attacks — the attacker triggers login attempts over and over until the user accidentally (or out of frustration) taps “Approve.”

The fix: number matching. Instead of just “Approve/Deny,” the login screen shows a number (say “47”), and the push notification asks you to enter that number. This prevents blind approvals.

Hardware Security Keys — The Gold Standard

Hardware keys like YubiKey and Google Titan are the strongest second factor available today. They use cryptographic protocols (FIDO U2F or FIDO2) that are phishing-resistant by design.

Here’s why they’re special:

  1. During registration, the key generates a public/private key pair bound to the specific website’s origin (e.g., https://accounts.google.com)
  2. During login, the server sends a challenge, and the key signs it with the private key
  3. The key checks the origin — if you’re on https://accounts.g00gle.com (a phishing site), the key refuses to sign because the origin doesn’t match
Legitimate site:
Server (accounts.google.com) → Challenge → YubiKey checks origin ✓ → Signs → Login ✓

Phishing site:
Server (accounts.g00gle.com) → Challenge → YubiKey checks origin ✗ → Refuses to sign

The key never sends the private key anywhere. It performs the cryptographic operation locally. Even if the server is compromised, the attacker can’t extract the key. And the origin check makes phishing literally impossible at the protocol level.

This is why Google reported zero successful phishing attacks on their 85,000+ employees after mandating hardware security keys.

Passwordless Authentication — The Future

Passwords are fundamentally flawed. They’re hard to remember, easy to steal, and people reuse them everywhere. The industry is moving toward passwordless authentication — and the leading standard is FIDO2/WebAuthn.

How WebAuthn Works

WebAuthn (Web Authentication API) lets you authenticate using a biometric (fingerprint, face) or a hardware key instead of a password. No password is ever created, transmitted, or stored.

The flow:

Registration:

  1. User clicks “Register” on a website
  2. Browser asks for biometric/key verification (Touch ID, Windows Hello, YubiKey)
  3. The device creates a public/private key pair specific to this website
  4. The public key is sent to the server. The private key never leaves the device

Authentication:

  1. User clicks “Login”
  2. Server sends a random challenge
  3. Browser asks for biometric/key verification
  4. Device signs the challenge with the private key
  5. Server verifies with the stored public key
Registration:
┌──────────┐         ┌──────────┐         ┌──────────┐
│  Server   │ ──1──> │  Browser  │ ──2──> │  Device   │
│           │        │           │        │ (TouchID) │
│ Store     │ <──4── │           │ <──3── │ Generate  │
│ public key│        │           │        │ key pair  │
└──────────┘         └──────────┘         └──────────┘

Authentication:
┌──────────┐         ┌──────────┐         ┌──────────┐
│  Server   │ ──1──> │  Browser  │ ──2──> │  Device   │
│ Send      │        │           │        │ Sign with │
│ challenge │        │           │        │ priv key  │
│           │ <──4── │           │ <──3── │           │
│ Verify    │        │           │        │           │
│ signature │        │           │        │           │
└──────────┘         └──────────┘         └──────────┘

No password. No shared secret. No phishing. The private key is bound to the device and the specific origin. It’s the same origin-checking mechanism that makes hardware keys phishing-resistant — but now it’s built into your laptop and phone.

Passkeys — WebAuthn for Everyone

Passkeys are Apple, Google, and Microsoft’s consumer-friendly implementation of WebAuthn. Instead of the key pair being locked to a single device, passkeys can be synced across your devices via iCloud Keychain, Google Password Manager, or Windows Hello.

This solves WebAuthn’s biggest usability problem — “what if I lose my device?” With passkeys, your credentials are backed up and available on all your devices.

The trade-off: synced passkeys are slightly less secure than device-bound keys (because the private key exists in more places). But they’re still vastly more secure than passwords, and the usability improvement makes adoption realistic at scale.

Authentication in the Enterprise — SSO and Federation

In an enterprise, users don’t log in to each application separately. They log in once, and they’re authenticated everywhere. This is Single Sign-On (SSO).

How SSO Works (Simplified)

  1. User tries to access App A
  2. App A redirects to the Identity Provider (IdP) — e.g., Okta, Azure AD, WSO2 IS
  3. User authenticates with the IdP (once)
  4. IdP issues a token/assertion and redirects back to App A
  5. User tries to access App B
  6. App B redirects to the same IdP
  7. IdP sees the user already has an active session → issues a token immediately (no login prompt)
  8. User is in — without typing credentials again
User → App A → "Not authenticated" → Redirect to IdP
                                           ↓
User → IdP → Login (username + password + MFA)
                                           ↓
IdP → Token → Redirect back to App A → Authenticated ✓

User → App B → "Not authenticated" → Redirect to IdP
                                           ↓
IdP → "Already authenticated" → Token → Redirect back to App B → Authenticated ✓

The protocols that make this possible — SAML 2.0 and OpenID Connect (OIDC) — deserve their own articles. We’ll cover OIDC and SAML later in this series.

The key point: the applications (called Service Providers or Relying Parties) never see the user’s password. They trust the IdP to authenticate the user and accept the token it issues. This is the foundation of federated identity.

Certificate-Based Authentication — mTLS

There’s one more authentication method worth mentioning, especially if you’re into API security or microservices — mutual TLS (mTLS).

Normal TLS (what HTTPS uses) only authenticates the server — your browser verifies the server’s certificate to make sure you’re talking to the real google.com. But the server doesn’t verify who you are through the TLS layer.

In mTLS, both sides present certificates:

Normal TLS:
Client → Server:  "Show me your certificate"
Server → Client:  "Here it is" (signed by trusted CA)
Client:           Verifies ✓

Mutual TLS:
Client → Server:  "Show me your certificate"
Server → Client:  "Here it is. Now show me yours."
Client → Server:  "Here's mine" (signed by trusted CA)
Both sides:       Verify ✓

mTLS is commonly used for:

  • Service-to-service authentication in microservices (Istio, Linkerd use it by default)
  • API authentication where both client and server need strong identity verification
  • Zero-trust architectures where every connection must be authenticated

It’s more complex to set up than token-based auth (you need a PKI infrastructure to issue and manage certificates), but it’s extremely secure — no passwords, no tokens to steal, and the authentication happens at the transport layer before any application code runs.

Putting It All Together — The Modern Auth Stack

In a modern application, authentication typically combines multiple layers:

┌─────────────────────────────────────────────────────────┐
│                    User Authenticates                     │
│                                                          │
│  Password (bcrypt/Argon2)  +  MFA (TOTP/WebAuthn)       │
│                          ↓                                │
│              Identity Provider (IdP)                      │
│         Okta / Azure AD / Keycloak / WSO2 IS             │
│                          ↓                                │
│              Token Issued (JWT / SAML Assertion)          │
│                          ↓                                │
│    ┌──────────┐  ┌──────────┐  ┌──────────┐             │
│    │  App A   │  │  App B   │  │  API GW  │             │
│    │ (OIDC)   │  │ (SAML)   │  │ (OAuth)  │             │
│    └──────────┘  └──────────┘  └──────────┘             │
│                                                          │
│    Each app validates the token and grants access         │
│    based on claims/roles → Access Control Models          │
└─────────────────────────────────────────────────────────┘
  1. The user proves their identity (password + MFA)
  2. A central IdP handles the authentication
  3. The IdP issues tokens to applications
  4. Applications validate tokens and make authorization decisions

Authentication answers “who are you?” — then hands off to authorization which answers “what can you do?”

Quick Reference — Authentication Methods Compared

Method Security Usability Phishing Resistant? Best For
Password only Low High No Nothing (don’t do this)
Password + SMS OTP Medium Medium No Legacy systems
Password + TOTP Medium-High Medium No (AitM) General use
Password + Push Medium-High High Partial Enterprise apps
Password + Hardware key Very High Medium Yes High-security accounts
Passwordless (WebAuthn) Very High High Yes The future
mTLS Very High Low (setup) N/A Service-to-service

Final Thoughts

Authentication has come a long way from plain-text passwords in a database. We’ve gone through the entire spectrum — from password hashing (bcrypt, salting) to sessions and tokens, from basic MFA to phishing-resistant hardware keys and passwordless WebAuthn.

If there’s one thing to take away from this article, it’s this: defense in depth. No single authentication method is perfect. Passwords get phished. TOTP can be intercepted in real-time. Even hardware keys can be lost. The strongest authentication systems layer multiple methods together and prepare for each one to fail.

And remember — authentication is just the first gate. Once you know who someone is, you still need to decide what they can do. That’s where access control models and the broader IAM framework take over.

Next up in this series — OpenID Connect (OIDC), the identity layer that powers “Sign in with Google” at the protocol level.

Stay secure!

ALSO READ
Exploiting a Stack Buffer Overflow on Windows
Apr 12, 2020 Exploit Development

In a previous tutorial we discusses how we can exploit a buffer overflow vulnerability on a Linux machine. I wen through all theories in depth and explained each step. Now today we are going to jump...

Exploiting a  Stack Buffer Overflow  on Linux
Apr 01, 2020 Exploit Development

Have you ever wondered how attackers gain control over remote servers? How do they just run some exploit and compromise a computer? If we dive into the actual context, there is no magic happening....

Basic concepts of Cryptography
Mar 01, 2020 Cryptography

Ever notice that little padlock icon in your browser's address bar? That's cryptography working silently in the background, protecting everything you do online. Whether you're sending an email,...

Remote Code Execution (RCE)
Jan 02, 2020 Application Security

Remote Code Execution (RCE) is the holy grail of application security vulnerabilities. It allows an attacker to execute arbitrary code on a remote server — and the consequences are as bad as it sounds. In this post, we'll go deep into RCE across multiple languages, including PHP, Java, Python, and Node.js.

> > >