Offensive Security Prep Pack for eJPT, OSCP, PNPT, OSWE, and OSEP— Practice Questions: Web Application Exploitation Domain
Test your Offensive Security knowledge (eJPT, OSCP, PNPT, OSWE, and OSEP) with 10 free practice questions from the Web Application Exploitation (OSWE-focused) domain. Includes detailed explanations and answers.
OSPP Practice Questions
Master the Web Application Exploitation (OSWE-focused) Domain
Test your knowledge in the Web Application Exploitation (OSWE-focused) domain with these 10 practice questions. Each question is designed to help you prepare for the OSPP certification exam with detailed explanations to reinforce your learning.
You are testing a Node.js/Express application that exposes a JSON-based login API:
// app.js
app.post('/api/login', async (req, res) => {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({ error: 'Missing credentials' });
}
const user = await db.users.findOne({ username: username });
if (!user) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Passwords are stored as bcrypt hashes
const ok = await bcrypt.compare(password, user.password);
if (!ok) {
return res.status(401).json({ error: 'Invalid credentials' });
}
return res.json({ token: signJwt({ id: user._id, role: user.role }) });
});
The db.users.findOne function is a thin wrapper around the MongoDB Node.js driver:
// db.js
exports.users = {
findOne: async (query) => {
return await client.db('app').collection('users').findOne(query);
}
};
You notice that the application uses body-parser with extended: true, and that it does not perform any type checking on username. Which of the following payloads is most likely to allow you to bypass authentication and log in as an arbitrary user without knowing their password?
Show Answer & Explanation
Correct Answer: A
Explanation: The core issue is that username is passed into the MongoDB query without type validation. With extended body parsing, an attacker can submit an object containing MongoDB operators (e.g., $ne) and change query semantics.
const user = await db.users.findOne({ username: username });
With payload A, the effective query becomes:
{ "username": { "$ne": null } }
This matches a user record where username is not null (often returning the first user). The other options either do not affect the DB query (B), are less predictable (C), or rely on incorrect bcrypt behavior (D).
You are performing a white-box assessment of a PHP-based bug tracking system. The application allows project managers to upload a project logo. You find the following code in upload_logo.php:
<?php
session_start();
require_once 'auth.php';
require_once 'db.php';
if (!isProjectManager($_SESSION['user_id'], $_POST['project_id'])) {
http_response_code(403);
die('Forbidden');
}
if (!isset($_FILES['logo']) || $_FILES['logo']['error'] !== UPLOAD_ERR_OK) {
die('Upload error');
}
$allowed = ['image/png', 'image/jpeg'];
if (!in_array($_FILES['logo']['type'], $allowed, true)) {
die('Invalid file type');
}
$ext = pathinfo($_FILES['logo']['name'], PATHINFO_EXTENSION);
$filename = 'logo_' . intval($_POST['project_id']) . '.' . $ext;
$target = __DIR__ . '/uploads/' . $filename;
if (!move_uploaded_file($_FILES['logo']['tmp_name'], $target)) {
die('Failed to move file');
}
$stmt = $db->prepare('UPDATE projects SET logo_path = ? WHERE id = ?');
$stmt->execute(['/uploads/' . $filename, $_POST['project_id']]);
header('Location: project.php?id=' . intval($_POST['project_id']));
In project.php you see:
<?php
$project_id = intval($_GET['id']);
$stmt = $db->prepare('SELECT name, logo_path FROM projects WHERE id = ?');
$stmt->execute([$project_id]);
$project = $stmt->fetch(PDO::FETCH_ASSOC);
if ($project && $project['logo_path']) {
echo '<img src="' . htmlspecialchars($project['logo_path'], ENT_QUOTES, 'UTF-8') . '" alt="Logo">';
}
Apache configuration includes:
<Directory /var/www/html/uploads>
Options -Indexes +ExecCGI
AddHandler application/x-httpd-php .php .phtml
AllowOverride None
Require all granted
</Directory>
You have a valid low-privileged account and can create a project where you are the project manager. You want RCE. Which strategy is the most realistic and effective given the code and configuration?
Show Answer & Explanation
Correct Answer: C
Explanation: The server trusts the client-supplied MIME type and lets you control the stored extension via the original filename. Apache executes .phtml as PHP in /uploads, enabling a direct upload-to-exec chain.
You are reviewing a Java DAO method:
public Product getProductById(String id) throws SQLException {
String sql = "SELECT id, name, price, description FROM products WHERE id = " + id;
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql);
if (rs.next()) {
Product p = new Product();
p.setId(rs.getInt("id"));
p.setName(rs.getString("name"));
p.setPrice(rs.getBigDecimal("price"));
p.setDescription(rs.getString("description"));
return p;
}
return null;
}
Controller:
@GetMapping("/product")
public String product(@RequestParam("id") String id, Model model) {
Product p = productDao.getProductById(id);
model.addAttribute("product", p);
return "product";
}
DB user has SELECT/INSERT/UPDATE/DELETE on products only; no privileges on users. Which attack path is most realistic to reach an auth bypass given constraints?
Show Answer & Explanation
Correct Answer: C
Explanation: Direct access to users is blocked by DB privileges. The realistic OSWE chain is to abuse what you can control (products) and pivot into an application logic weakness (e.g., pricing/checkout/role logic).
Flask admin endpoint:
from flask import Flask, request, render_template_string, session, abort
app = Flask(__name__)
app.secret_key = 'super-secret-key'
@app.route('/admin/panel')
def admin_panel():
if not session.get('is_admin'):
abort(403)
widget = request.args.get('widget', 'stats.html')
template = '''
{% include 'base.html' %}
{% include 'widgets/' + widget %}
'''
return render_template_string(template, user=session.get('user'))
You can set session['is_admin'] = True via a weak cookie. You cannot upload files. Which payload in widget is most likely to yield RCE?
Show Answer & Explanation
Correct Answer: D
Explanation: You must break out of the Jinja {% include %} context before executing Jinja expressions. D performs the correct block escape and then executes a known Jinja gadget chain.
Login + JWT code:
// LoginServlet.java (excerpt)
String token = JwtUtil.sign(user.getId(), user.getRole());
Cookie c = new Cookie("auth", token);
c.setHttpOnly(true);
c.setPath("/");
resp.addCookie(c);
// JwtUtil.java (excerpt)
private static final String SECRET = "dev-secret";
public static String sign(int userId, String role) {
Algorithm alg = Algorithm.HMAC256(SECRET);
return JWT.create()
.withClaim("uid", userId)
.withClaim("role", role)
.sign(alg);
}
A unit test exists and is deployed with the app:
// JwtUtilTest.java (excerpt)
@Test
public void testSign() {
String token = JwtUtil.sign(1, "admin");
System.out.println(token);
}
Which is the most realistic way to gain admin access to /account without valid credentials?
Show Answer & Explanation
Correct Answer: B
Explanation: The repository includes deterministic signing logic and a test that generates an admin token using the same hard-coded secret. That is the most direct, reliable path compared to speculative bypass techniques.
Search helper concatenates ORDER BY:
async function searchProducts(term, orderBy) {
const sql = `
SELECT id, name, price
FROM products
WHERE name LIKE ?
ORDER BY ${orderBy} ASC
LIMIT 20
`;
return pool.query(sql, [`%${term}%`]);
}
Caller whitelists sort:
const orderBy = req.query.sort || 'name';
if (!['name', 'price'].includes(orderBy)) {
orderBy = 'name';
}
Which approach is most accurate and realistic from an OSWE perspective?
Show Answer & Explanation
Correct Answer: D
Explanation: term is a bound parameter; injected SQL remains literal string data. orderBy is constrained to fixed column names. The OSWE-accurate move is to validate this path as safe and pivot to other code paths for real injection.
Password reset route:
const payload = jwt.verify(token, process.env.JWT_SECRET || 'dev-secret');
Staging leaks: [DEBUG] Using default JWT secret. You want to escalate to admin@example.com. Which approach is most reliable?
Show Answer & Explanation
Correct Answer: C
Explanation: The default secret is confirmed in staging. Forging a valid token with the known secret is deterministic, fastest, and most reliable.
Coupon controller:
String sql = "SELECT * FROM coupons WHERE code = '" + code + "'";
Coupon coupon = jdbcTemplate.queryForObject(sql, new CouponRowMapper());
Errors not shown to user; you can measure timing and see logs. Most reliable exfil approach?
Show Answer & Explanation
Correct Answer: A
Explanation: When output is not reflected and error detail is uncertain, time-based blind extraction is the most consistently reliable OSWE-style primitive.
Download handler:
$baseDir = __DIR__ . '/uploads/' . $ticketId . '/';
$path = realpath($baseDir . $file);
if ($path === false || strpos($path, $baseDir) !== 0) {
http_response_code(400);
exit('Invalid file');
}
You want to read /var/log/nginx/access.log without uploading new files. Which approach is most likely?
Show Answer & Explanation
Correct Answer: C
Explanation: In real-world patterns, symlink tricks are the primary bypass class when traversal is blocked and you cannot upload. (If no symlink exists and you cannot create one, the practical exploitability depends on other filesystem primitives.)
DAO uses PreparedStatement for status and whitelists sort:
// Whitelist for sort column
if (!sort.matches("^[a-z_]+$") ||
!(sort.equals("created_at") || sort.equals("priority") || sort.equals("id"))) {
sort = "created_at";
}
String sql = "SELECT id, title, status, owner_id FROM tickets WHERE status = ? ORDER BY " + sort;
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, status);
Which is the most realistic and effective way to achieve time-based blind SQLi under default PostgreSQL behavior?
Show Answer & Explanation
Correct Answer: D
Explanation: status is bound via PreparedStatement, and sort only allows three literal column names with a regex that disallows spaces, commas, parentheses, operators, or functions. Payloads that attempt expressions or stacking will not pass validation.
Ready to Accelerate Your Offensive Security Preparation?
Join thousands of professionals who are advancing their careers through expert certification preparation with FlashGenius.
- ✅ Unlimited practice questions across all OSPP domains
- ✅ Full-length exam simulations with real-time scoring
- ✅ AI-powered performance tracking and weak area identification
- ✅ Personalized study plans with adaptive learning
- ✅ Mobile-friendly platform for studying anywhere, anytime
- ✅ Expert explanations and study resources
Already have an account? Sign in here
About Offensive Certification Pack
The Offensive Security Prep Pack for eJPT, OSCP, PNPT, OSWE, and OSEP validates your expertise in web application exploitation and other critical domains. Our practice questions are crafted to mirror exam-style reasoning and help you identify knowledge gaps before test day.
Offensive Security Prep Pack: EJPT, OSCP, PNPT, OSWE & OSEP
Train for multiple offensive security certifications in one place. Get domain-based drills, mixed-mode practice tests, and realistic red-team scenarios that mirror how EJPT, OSCP, PNPT, OSWE & OSEP actually feel on exam day.
- 10+ focused domains covering networking, web, AD, privilege escalation & more
- Exam-style MCQs, methodology drills, and chained attack paths
- Mixed practice sets to simulate end-to-end engagements
- Detailed explanations to turn every miss into a lesson
Ideal if you're targeting 2–3 OffSec-style certifications and want one unified prep pack.
Try the Offensive Security Prep Pack