Skip to content

C#: ASP.NET Core like members are tainted#9393

Merged
michaelnebel merged 6 commits into
github:mainfrom
michaelnebel:csharp/asptaintedmember
Jun 20, 2022
Merged

C#: ASP.NET Core like members are tainted#9393
michaelnebel merged 6 commits into
github:mainfrom
michaelnebel:csharp/asptaintedmember

Conversation

@michaelnebel

Copy link
Copy Markdown
Contributor

Consider all properties of ASP.NET Core like objects to also be sources of tainted data.

I have taken the liberty to collapse a couple of remote flow source types into one type (everything related to ASP.Net Core) and then only perceive members of these to be tainted as well instead of doing it generally for all remote flow sources.

@michaelnebel

Copy link
Copy Markdown
Contributor Author

DCA run looks fine.

@michaelnebel michaelnebel marked this pull request as ready for review June 2, 2022 07:02
@michaelnebel michaelnebel requested a review from a team as a code owner June 2, 2022 07:02
@michaelnebel michaelnebel added the no-change-note-required This PR does not need a change note label Jun 2, 2022

@tamasvajk tamasvajk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add a change note. It has an impact on a wide audience.

@michaelnebel

Copy link
Copy Markdown
Contributor Author

I think we should add a change note. It has an impact on a wide audience.

Makes sense. I will add a change note.

@michaelnebel michaelnebel removed the no-change-note-required This PR does not need a change note label Jun 2, 2022
@michaelnebel

Copy link
Copy Markdown
Contributor Author

Ran the UnsafeDeserializationUnstrustedData query using MRVA. I know other queries are affected as well, but maybe this gives us an indication that the change is safe (this is execution against the top 100 projects (no guarantee that there are any ASP.NET projects there)). No results.

image

@michaelnebel michaelnebel requested a review from tamasvajk June 2, 2022 12:31
Comment on lines +6 to +22
public class ViewModel
{
public string RequestId { get; set; }

public object Query;
}

public class TestController : Controller
{
public object MyAction(ViewModel viewModel)
{
throw null;
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be sure, could you add a class without any reference to it?

    public class UnusedViewModel
    {
        public string RequestId { get; set; }

        public object Query;
    }

My expectation would be that its properties don't show up in remoteFlowSourceMembers.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is correct. In Remote.qll RemoteFlowSource are only extended on types used as parameter types on methods in Controller like classes.

@michaelnebel michaelnebel requested a review from tamasvajk June 15, 2022 07:24
Comment on lines +6 to +14
public class ViewModel
{
public string RequestId { get; set; }

public object Query;
}

@tamasvajk tamasvajk Jun 15, 2022

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit picking, but what happens with get-only properties and private or static members?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, they are also included. There is no further restrictions on the Assignable members. Let's change this such that it is only public and non static assignable members.
Good catch!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also - this is not nit picking! Really good that you ask these questions!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also fine-grain it even more. Do you have any special opinion on, which members we should included/exclude?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not an expert on this. A quick google search revealed that (of course) this can be customized in asp.net. But in any case, I think if we mimic what the DefaultModelBinder does, we probably handle 95% of the cases correctly. I couldn't find an explicit list of the requirements on members, but it looks like only public non-static properties are handled. Also, properties with private setters are excluded as per dotnet/aspnetcore#38243. Also, maybe the class/record needs to have a default constructor. But I think we should dig a bit more deeply into the documentation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tamasvajk : Thank you!
Ah yes, I think you are right. I read some of this (I know it is old): https://docs.microsoft.com/en-us/archive/msdn-magazine/2012/february/asp-net-mvc-the-features-and-foibles-of-asp-net-mvc-model-binding

It doesn't explicitly state that properties should be get/set, but it seems like it is implicitly assumed and this could serve is a conservative extension of the existing logic (cover more with lower risk of false positives).
My suggestion would be that we take all public properties with public getters and setters and all public non-readonly fields. No statics allowed of course. Then we should be on the safe side and also cover most cases!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can ignore fields altogether. There are some commonly used attributes to specify from where data should be bound. For example if data is taken from the request body, then FromBody is used: https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.frombodyattribute?view=aspnetcore-6.0. These attributes have no Field target, so I think we can safely ignore fields.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright! ASP.NET is complicated :-) It looks like the canonical examples all uses public (non static) auto implemented properties with public getters and setters. Maybe that is sufficiently conservative as a starting point.

@michaelnebel michaelnebel requested a review from tamasvajk June 15, 2022 10:55
@michaelnebel michaelnebel force-pushed the csharp/asptaintedmember branch from b512a19 to 0fa7ddf Compare June 15, 2022 13:15
@michaelnebel michaelnebel force-pushed the csharp/asptaintedmember branch from 0fa7ddf to f7f83a0 Compare June 16, 2022 06:39
@michaelnebel michaelnebel force-pushed the csharp/asptaintedmember branch from f7f83a0 to 9211d75 Compare June 16, 2022 06:43

@tamasvajk tamasvajk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

@michaelnebel michaelnebel merged commit 7020363 into github:main Jun 20, 2022
@michaelnebel michaelnebel deleted the csharp/asptaintedmember branch June 20, 2022 10:11
@felickz

felickz commented Jun 30, 2022

Copy link
Copy Markdown
Contributor

Confirmed - Fixed in 2.10.0 CLI bundle and 0.2.0 codeql/csharp-queries (changelog)

Forcing Action to 2.10.0 lights up a bunch of alerts that were missing for me ( new alerts on complex types)

abstract class AspNetCoreRemoteFlowSource extends RemoteFlowSource { }

/**
* Data flow for AST.NET Core.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo

Comment on lines +180 to +189
private class AspNetCoreRemoteFlowSourceMember extends TaintTracking::TaintedMember {
AspNetCoreRemoteFlowSourceMember() {
this.getDeclaringType() = any(AspNetCoreRemoteFlowSource source).getType() and
this.isPublic() and
not this.isStatic() and
exists(Property p | p = this |
p.isAutoImplemented() and p.getGetter().isPublic() and p.getSetter().isPublic()
)
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be simplified a bit:

private class AspNetCoreRemoteFlowSourceMember extends TaintTracking::TaintedMember, Property {
  AspNetCoreRemoteFlowSourceMember() {
    this.getDeclaringType() = any(AspNetCoreRemoteFlowSource source).getType() and
    this.isPublic() and
    not this.isStatic() and
    this.isAutoImplemented() and
    this.getGetter().isPublic() and
    this.getSetter().isPublic()
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants