Skip to content

Commit 6a78aa7

Browse files
authored
Merge pull request github#6461 from tamasvajk/feature/service-stack
C#: Add ServiceStack support
2 parents b73a2f7 + f015cea commit 6a78aa7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+39363
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
lgtm,codescanning
2+
* added support for ServiceStack framework with support for SQL injection, XSS and external API calls
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
Framework name,URL,Namespace prefixes
22
System,,System.* System
3+
ServiceStack,https://servicestack.net/,ServiceStack.* ServiceStack

csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ private module Frameworks {
8888
private import semmle.code.csharp.security.dataflow.flowsinks.Html
8989
private import semmle.code.csharp.frameworks.System
9090
private import semmle.code.csharp.security.dataflow.XSSSinks
91+
private import semmle.code.csharp.frameworks.ServiceStack
9192
}
9293

9394
/**

csharp/ql/lib/semmle/code/csharp/frameworks/ServiceStack.qll

Lines changed: 321 additions & 0 deletions
Large diffs are not rendered by default.

csharp/ql/lib/semmle/code/csharp/security/dataflow/CodeInjectionQuery.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ private import semmle.code.csharp.security.dataflow.flowsources.Remote
77
private import semmle.code.csharp.security.dataflow.flowsources.Local
88
private import semmle.code.csharp.frameworks.system.codedom.Compiler
99
private import semmle.code.csharp.security.Sanitizers
10+
private import semmle.code.csharp.dataflow.ExternalFlow
1011

1112
/**
1213
* A data flow source for user input treated as code vulnerabilities.
@@ -79,3 +80,8 @@ class RoslynCSharpScriptSink extends Sink {
7980
)
8081
}
8182
}
83+
84+
/** Code injection sinks defined through CSV models. */
85+
private class ExternalCodeInjectionExprSink extends Sink {
86+
ExternalCodeInjectionExprSink() { sinkNode(this, "code") }
87+
}

csharp/ql/lib/semmle/code/csharp/security/dataflow/SqlInjectionQuery.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ private import semmle.code.csharp.security.dataflow.flowsources.Remote
77
private import semmle.code.csharp.security.dataflow.flowsources.Local
88
private import semmle.code.csharp.frameworks.Sql
99
private import semmle.code.csharp.security.Sanitizers
10+
private import semmle.code.csharp.dataflow.ExternalFlow
1011

1112
/**
1213
* A source specific to SQL injection vulnerabilities.
@@ -51,6 +52,11 @@ class SqlInjectionExprSink extends Sink {
5152
SqlInjectionExprSink() { exists(SqlExpr s | this.getExpr() = s.getSql()) }
5253
}
5354

55+
/** SQL sinks defined through CSV models. */
56+
private class ExternalSqlInjectionExprSink extends Sink {
57+
ExternalSqlInjectionExprSink() { sinkNode(this, "sql") }
58+
}
59+
5460
private class SimpleTypeSanitizer extends Sanitizer, SimpleTypeSanitizedExpr { }
5561

5662
private class GuidSanitizer extends Sanitizer, GuidSanitizedExpr { }

csharp/ql/lib/semmle/code/csharp/security/dataflow/XSSSinks.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ private import semmle.code.csharp.frameworks.system.web.UI
1010
private import semmle.code.csharp.security.dataflow.flowsinks.Html
1111
private import semmle.code.csharp.security.dataflow.flowsinks.Remote
1212
private import semmle.code.csharp.dataflow.ExternalFlow
13+
private import semmle.code.csharp.frameworks.ServiceStack::XSS
1314

1415
/**
1516
* A data flow sink for cross-site scripting (XSS) vulnerabilities.

csharp/ql/lib/semmle/code/csharp/security/dataflow/flowsinks/ExternalLocationSink.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import csharp
66
private import Remote
77
private import semmle.code.csharp.commons.Loggers
88
private import semmle.code.csharp.frameworks.system.Web
9+
private import semmle.code.csharp.dataflow.ExternalFlow
910

1011
/**
1112
* An external location sink.
@@ -16,6 +17,10 @@ private import semmle.code.csharp.frameworks.system.Web
1617
*/
1718
abstract class ExternalLocationSink extends DataFlow::ExprNode { }
1819

20+
private class ExternalModelSink extends ExternalLocationSink {
21+
ExternalModelSink() { sinkNode(this, "remote") }
22+
}
23+
1924
/**
2025
* An argument to a call to a method on a logger class.
2126
*/
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using ServiceStack;
4+
using System.Threading.Tasks;
5+
using System;
6+
using Microsoft.Extensions.ObjectPool;
7+
using System.IO;
8+
9+
namespace ServiceStackTest
10+
{
11+
public class ResponseDto { }
12+
public class ReqDto1 : IReturn<ResponseDto> { }
13+
14+
public class ReqDto2 : IReturnVoid { }
15+
16+
public class C
17+
{
18+
public async Task M()
19+
{
20+
var client = new JsonServiceClient("");
21+
22+
client.DeserializeFromStream<object>(new MemoryStream()); // not a sink
23+
24+
client.Get(new ReqDto1());
25+
client.Get(new ReqDto2());
26+
client.Get<ResponseDto>("relativeOrAbsoluteUrl"); // not a sink
27+
client.Get<ResponseDto>(new object());
28+
client.Get("relativeOrAbsoluteUrl"); // not a sink
29+
client.Get(new object());
30+
31+
await client.GetAsync<ResponseDto>("relativeOrAbsoluteUrl"); // not a sink
32+
await client.GetAsync<ResponseDto>(new object());
33+
await client.GetAsync(new ReqDto1());
34+
await client.GetAsync(new ReqDto2());
35+
36+
37+
client.CustomMethod("GET", new ReqDto2());
38+
client.CustomMethod<ResponseDto>("GET", "relativeOrAbsoluteUrl", new ReqDto1());
39+
client.CustomMethod<ResponseDto>("GET", new ReqDto1());
40+
client.CustomMethod<ResponseDto>("GET", new object());
41+
client.CustomMethod("GET", "relativeOrAbsoluteUrl", new object());
42+
client.CustomMethod("GET", (IReturnVoid)null);
43+
await client.CustomMethodAsync("GET", new ReqDto2());
44+
await client.CustomMethodAsync<ResponseDto>("GET", "relativeOrAbsoluteUrl", new ReqDto1());
45+
await client.CustomMethodAsync<ResponseDto>("GET", new ReqDto1());
46+
await client.CustomMethodAsync<ResponseDto>("GET", new object());
47+
48+
client.DownloadBytes("GET", "requestUri", new object());
49+
await client.DownloadBytesAsync("GET", "relativeOrAbsoluteUrl", new object());
50+
51+
client.Head(new object());
52+
client.Patch(new object());
53+
client.Post(new object());
54+
client.Put(new object());
55+
56+
client.Send<ResponseDto>(new object());
57+
client.Publish(new ReqDto1());
58+
client.SendOneWay(new object());
59+
}
60+
}
61+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using ServiceStack;
4+
using System.Threading.Tasks;
5+
using System;
6+
using Microsoft.AspNetCore.Components.Forms;
7+
using ServiceStack.OrmLite;
8+
9+
namespace ServiceStackTest
10+
{
11+
public class Table
12+
{
13+
public int Column { get; set; }
14+
}
15+
16+
public class Sql
17+
{
18+
public static async Task M()
19+
{
20+
ServiceStack.OrmLite.SqlExpression<int> expr = null;
21+
22+
expr = expr.Select<Table>(t => t.Column); // ok
23+
24+
expr = expr
25+
.UnsafeAnd("SQL")
26+
.UnsafeFrom("SQL")
27+
.UnsafeGroupBy("SQL")
28+
.UnsafeHaving("SQL")
29+
.UnsafeOr("SQL")
30+
.UnsafeOrderBy("SQL")
31+
.UnsafeSelect("SQL")
32+
.UnsafeWhere("SQL");
33+
34+
var untyped = expr.GetUntypedSqlExpression();
35+
36+
untyped
37+
.UnsafeAnd("SQL")
38+
.UnsafeFrom("SQL")
39+
.UnsafeOr("SQL")
40+
.UnsafeSelect("SQL")
41+
.UnsafeWhere("SQL")
42+
.Where("SQL"); // safe
43+
44+
System.Data.IDbConnection conn = null;
45+
46+
var row = conn.SingleById<Table>(1); // ok
47+
48+
var rows = conn.Select<Table>(typeof(Table), "SQL", null);
49+
rows = await conn.SelectAsync<Table>(typeof(Table), "SQL", null);
50+
51+
var count = conn.RowCount("SQL");
52+
count = await conn.RowCountAsync("SQL");
53+
54+
conn.ExecuteSql("SQL", null);
55+
await conn.ExecuteSqlAsync("SQL", null);
56+
}
57+
58+
public static async Task Redis()
59+
{
60+
ServiceStack.Redis.IRedisClient client = null;
61+
62+
client.SetValue("key", "value"); // ok
63+
64+
var s = client.LoadLuaScript("script");
65+
client.ExecLua("script", new[] { "" }, new[] { "" });
66+
client.ExecLuaSha("SHA", new[] { "" }, new[] { "" }); // ok
67+
client.Custom("command", "arg"); // false negative, params sinks doesn't work
68+
69+
ServiceStack.Redis.IRedisClientAsync asyncClient = null;
70+
s = await asyncClient.LoadLuaScriptAsync("script");
71+
asyncClient.ExecLuaAsync("script", new[] { "" }, new[] { "" });
72+
}
73+
}
74+
}

0 commit comments

Comments
 (0)