CVE-2023-34105: Improper Neutralization of Special Elements used in a Command ('Command Injection') (CWE-77)
value: SRS is a real-time video server supporting RTMP, WebRTC, HLS, HTTP-FLV, SRT, MPEG-DASH, and GB28181. Prior to versions 5.0.157, 5.0-b1, and 6.0.48, SRS's `api-server` server is vulnerable to a drive-by command injection. An attacker may send a request to the `/api/v1/snapshots` endpoint containing any commands to be executed as part of the body of the POST request. This issue may lead to Remote Code Execution (RCE). Versions 5.0.157, 5.0-b1, and 6.0.48 contain a fix.
CWE description: The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.
CVSS v3 base score: 7.5
Published: 2023-06-12T17:15Z
Repository: https://github.com/ossrs/srs
Language: C++
Files changed: trunk/doc/CHANGELOG.md, trunk/research/api-server/server.go, trunk/src/core/srs_core_version5.hpp, trunk/src/core/srs_core_version6.hpp
Commit date: 2023-06-05 16:38:42 +0800
Commit message: Fix command injection in api-server for HTTP callback. v5.0.157, v6.0.48

Diff: diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md
index 294d048c5..99770a6b3 100644
--- a/trunk/doc/CHANGELOG.md
+++ b/trunk/doc/CHANGELOG.md
@@ -6,10 +6,11 @@ The changelog for SRS.
 
 <a name="v6-changes"></a>
 
 ## SRS 6.0 Changelog
 
+* v6.0, 2023-06-05, Fix command injection in demonstration api-server for HTTP callback. v6.0.48
 * v6.0, 2023-06-05, Merge [#3565](https://github.com/ossrs/srs/pull/3565): DTLS: Use bio callback to get fragment packet. v6.0.47 (#3565)
 * v6.0, 2023-05-29, Merge [#3513](https://github.com/ossrs/srs/pull/3513): SSL: Fix SSL_get_error get the error of other coroutine. v6.0.46 (#3513)
 * v6.0, 2023-05-14, Merge [#3534](https://github.com/ossrs/srs/pull/3534): Replace sprintf with snprintf to eliminate compile warnings. v6.0.45 (#3534)
 * v6.0, 2023-05-13, Merge [#3541](https://github.com/ossrs/srs/pull/3541): asan: Fix memory leak in asan by releasing global IPs when run_directly_or_daemon fails. v6.0.44 (#3541)
 * v6.0, 2023-05-12, Merge [#3539](https://github.com/ossrs/srs/pull/3539): WHIP: Improve HTTP DELETE for notifying server unpublish event. v6.0.43 (#3539)
@@ -59,10 +60,11 @@ The changelog for SRS.
 
 <a name="v5-changes"></a>
 
 ## SRS 5.0 Changelog
 
+* v5.0, 2023-06-05, Fix command injection in demonstration api-server for HTTP callback. v5.0.157
 * v5.0, 2023-06-05, Merge [#3565](https://github.com/ossrs/srs/pull/3565): DTLS: Use bio callback to get fragment packet. v5.0.156 (#3565)
 * v5.0, 2023-05-29, Merge [#3513](https://github.com/ossrs/srs/pull/3513): SSL: Fix SSL_get_error get the error of other coroutine. v5.0.155 (#3513)
 * v5.0, 2023-05-13, Merge [#3541](https://github.com/ossrs/srs/pull/3541): asan: Fix memory leak in asan by releasing global IPs when run_directly_or_daemon fails. v5.0.154 (#3541)
 * v5.0, 2023-05-12, Merge [#3539](https://github.com/ossrs/srs/pull/3539): WHIP: Improve HTTP DELETE for notifying server unpublish event. v5.0.153 (#3539)
 * v5.0, 2023-03-27, Merge [#3450](https://github.com/ossrs/srs/pull/3450): WebRTC: Error message carries the SDP when failed. v5.0.151 (#3450)
diff --git a/trunk/research/api-server/server.go b/trunk/research/api-server/server.go
index 8942d8c41..aa379528b 100644
--- a/trunk/research/api-server/server.go
+++ b/trunk/research/api-server/server.go
@@ -398,14 +398,22 @@ func (v *SnapshotJob) do(ffmpegPath, inputUrl string) (err error) {
 	}
 
 	normalPicPath := path.Join(outputPicDir, fmt.Sprintf("%v", v.Stream)+"-%03d.png")
 	bestPng := path.Join(outputPicDir, fmt.Sprintf("%v-best.png", v.Stream))
 
-	param := fmt.Sprintf("%v -i %v -vf fps=1 -vcodec png -f image2 -an -y -vframes %v -y %v", ffmpegPath, inputUrl, v.vframes, normalPicPath)
-	log.Println(fmt.Sprintf("start snapshot, cmd param=%v", param))
+	params := []string{
+		"-i", inputUrl,
+		"-vf", "fps=1",
+		"-vcodec", "png",
+		"-f", "image2",
+		"-an",
+		"-vframes", strconv.Itoa(v.vframes),
+		"-y", normalPicPath,
+	}
+	log.Println(fmt.Sprintf("start snapshot, cmd param=%v %v", ffmpegPath, strings.Join(params, " ")))
 	timeoutCtx, _ := context.WithTimeout(v.cancelCtx, v.timeout)
-	cmd := exec.CommandContext(timeoutCtx, "/bin/bash", "-c", param)
+	cmd := exec.CommandContext(timeoutCtx, ffmpegPath, params...)
 	if err = cmd.Run(); err != nil {
 		log.Println(fmt.Sprintf("run snapshot %v cmd failed, err is %v", v.Tag(), err))
 		return
 	}
 
diff --git a/trunk/src/core/srs_core_version5.hpp b/trunk/src/core/srs_core_version5.hpp
index 982777dba..7c9752a0b 100644
--- a/trunk/src/core/srs_core_version5.hpp
+++ b/trunk/src/core/srs_core_version5.hpp
@@ -7,8 +7,8 @@
 #ifndef SRS_CORE_VERSION5_HPP
 #define SRS_CORE_VERSION5_HPP
 
 #define VERSION_MAJOR       5
 #define VERSION_MINOR       0
-#define VERSION_REVISION    156
+#define VERSION_REVISION    157
 
 #endif
diff --git a/trunk/src/core/srs_core_version6.hpp b/trunk/src/core/srs_core_version6.hpp
index 4f6b719fb..4d2de5ddb 100644
--- a/trunk/src/core/srs_core_version6.hpp
+++ b/trunk/src/core/srs_core_version6.hpp
@@ -7,8 +7,8 @@
 #ifndef SRS_CORE_VERSION6_HPP
 #define SRS_CORE_VERSION6_HPP
 
 #define VERSION_MAJOR       6
 #define VERSION_MINOR       0
-#define VERSION_REVISION    47
+#define VERSION_REVISION    48
 
 #endif

Vulnerable code: 	param := fmt.Sprintf("%v -i %v -vf fps=1 -vcodec png -f image2 -an -y -vframes %v -y %v", ffmpegPath, inputUrl, v.vframes, normalPicPath)
	log.Println(fmt.Sprintf("start snapshot, cmd param=%v", param))
	cmd := exec.CommandContext(timeoutCtx, "/bin/bash", "-c", param)
#define VERSION_REVISION    156
#define VERSION_REVISION    47
Fixed code: * v6.0, 2023-06-05, Fix command injection in demonstration api-server for HTTP callback. v6.0.48
* v5.0, 2023-06-05, Fix command injection in demonstration api-server for HTTP callback. v5.0.157
	params := []string{
		"-i", inputUrl,
		"-vf", "fps=1",
		"-vcodec", "png",
		"-f", "image2",
		"-an",
		"-vframes", strconv.Itoa(v.vframes),
		"-y", normalPicPath,
	}
	log.Println(fmt.Sprintf("start snapshot, cmd param=%v %v", ffmpegPath, strings.Join(params, " ")))
	cmd := exec.CommandContext(timeoutCtx, ffmpegPath, params...)
#define VERSION_REVISION    157
#define VERSION_REVISION    48