In .NET, you may use a capture stack to grab all the repeated captures.
A regex like
##(?:\[([^][]*)])+##
will find ##
, then match and capture any amount of strings like [
+ texts-with-no-brackets
+ ]
and all these texts-with-no-brackets
will be pushed into a CaptureCollection that is associated with capture group 1.
See the regex demo online

In C#, you would use the following code:
var s = "My test string is ##[FirstVal][SecondVal]##";
var myvalues = Regex.Matches(s, @"##(?:\[([^][]*)])+##")
.Cast<Match>()
.SelectMany(m => m.Groups[1].Captures
.Cast<Capture>()
.Select(t => t.Value));
Console.WriteLine(string.Join(", ", myvalues));
See the C# demo
Mind you can do a similar thing with Python PyPi regex
module.