18a0c923d0
The pack name has been sanitized so an attacker cannot upload a media file called pack.json with their own handcrafted list of emoji files as arbitrary files on the filesystem and then call the emoji pack archive download endpoint with a pack name crafted to the location of the media file they uploaded which tricks Pleroma into generating a zip file of the target files the attacker wants to download. The attack only works if the Pleroma instance does not have the AnonymizeFilename upload filter enabled, which is currently the default. Reported by: graf@poast.org
97 lines
2.7 KiB
Elixir
97 lines
2.7 KiB
Elixir
# Pleroma: A lightweight social networking server
|
|
# Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
defmodule Pleroma.Emoji.PackTest do
|
|
use Pleroma.DataCase
|
|
alias Pleroma.Emoji.Pack
|
|
|
|
@emoji_path Path.join(
|
|
Pleroma.Config.get!([:instance, :static_dir]),
|
|
"emoji"
|
|
)
|
|
|
|
setup do
|
|
pack_path = Path.join(@emoji_path, "dump_pack")
|
|
File.mkdir(pack_path)
|
|
|
|
File.write!(Path.join(pack_path, "pack.json"), """
|
|
{
|
|
"files": { },
|
|
"pack": {
|
|
"description": "Dump pack", "homepage": "https://pleroma.social",
|
|
"license": "Test license", "share-files": true
|
|
}}
|
|
""")
|
|
|
|
{:ok, pack} = Pleroma.Emoji.Pack.load_pack("dump_pack")
|
|
|
|
on_exit(fn ->
|
|
File.rm_rf!(pack_path)
|
|
end)
|
|
|
|
{:ok, pack: pack}
|
|
end
|
|
|
|
describe "add_file/4" do
|
|
test "add emojies from zip file", %{pack: pack} do
|
|
file = %Plug.Upload{
|
|
content_type: "application/zip",
|
|
filename: "emojis.zip",
|
|
path: Path.absname("test/fixtures/emojis.zip")
|
|
}
|
|
|
|
{:ok, updated_pack} = Pack.add_file(pack, nil, nil, file)
|
|
|
|
assert updated_pack.files == %{
|
|
"a_trusted_friend-128" => "128px/a_trusted_friend-128.png",
|
|
"auroraborealis" => "auroraborealis.png",
|
|
"baby_in_a_box" => "1000px/baby_in_a_box.png",
|
|
"bear" => "1000px/bear.png",
|
|
"bear-128" => "128px/bear-128.png"
|
|
}
|
|
|
|
assert updated_pack.files_count == 5
|
|
end
|
|
end
|
|
|
|
test "returns error when zip file is bad", %{pack: pack} do
|
|
file = %Plug.Upload{
|
|
content_type: "application/zip",
|
|
filename: "emojis.zip",
|
|
path: Path.absname("test/instance_static/emoji/test_pack/blank.png")
|
|
}
|
|
|
|
assert Pack.add_file(pack, nil, nil, file) == {:error, :einval}
|
|
end
|
|
|
|
test "returns pack when zip file is empty", %{pack: pack} do
|
|
file = %Plug.Upload{
|
|
content_type: "application/zip",
|
|
filename: "emojis.zip",
|
|
path: Path.absname("test/fixtures/empty.zip")
|
|
}
|
|
|
|
{:ok, updated_pack} = Pack.add_file(pack, nil, nil, file)
|
|
assert updated_pack == pack
|
|
end
|
|
|
|
test "add emoji file", %{pack: pack} do
|
|
file = %Plug.Upload{
|
|
filename: "blank.png",
|
|
path: "#{@emoji_path}/test_pack/blank.png"
|
|
}
|
|
|
|
{:ok, updated_pack} = Pack.add_file(pack, "test_blank", "test_blank.png", file)
|
|
|
|
assert updated_pack.files == %{
|
|
"test_blank" => "test_blank.png"
|
|
}
|
|
|
|
assert updated_pack.files_count == 1
|
|
end
|
|
|
|
test "load_pack/1 ignores path traversal in a forged pack name", %{pack: pack} do
|
|
assert {:ok, ^pack} = Pack.load_pack("../../../../../dump_pack")
|
|
end
|
|
end
|